Migration of QtMvvm from github
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

510 lines
22 KiB

/*!
@class QtMvvm::ServiceRegistry
This is the class responsible for the dependency injection (DI) part. All services registered
with the registry are available for DI. When using lazy initialization, services themselves
can also have dependencies to be injected. When the registry creates them it will
automatically inject them. Automatic DI is also done for ViewModel created by the CoreApp.
@note If a service has a slot named `qtmvvm_init()` it is called automatically by the registry
right after all dependant services have been injected.
The following example shows how to use DI. The first shows how to use it with a simple,
interface-less service for an already created object:
@code{.cpp}
// service.h
class Service : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE explicit Service(QObject *parent = nullptr); //required signature
public Q_SLOTS:
void baum();
void qtmvvm_init(); //is called by the registry
};
// myclass.h
class MyClass : public QObject
{
Q_OBJECT
QTMVVM_INJECT_PROP(Service*, service, _service)
//...
private:
Service *_service;
};
//main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtMvvm::ServiceRegistry::instance()->registerObject<Service>();
//...
auto myObj = new MyClass(parent);
QtMvvm::ServiceRegistry::instance()->injectServices(myObj);
// _service is now initialized via a valid Service
}
@endcode
The second example shows how to use it for interface based services and on objects that are
created via the registry:
@code{.cpp}
// iservice.h
class IService
{
public:
virtual inline ~IService() = default;
public Q_SLOTS:
virtual void baum() = 0;
};
#define IServiceIid "com.example.myapp.IService"
Q_DECLARE_INTERFACE(IService, IServiceIid)
// service.h
class Service : public QObject, public IService
{
Q_OBJECT
Q_INTERFACES(IService)
public:
Q_INVOKABLE explicit Service(QObject *parent = nullptr); //required signature
public Q_SLOTS:
void baum() override;
void qtmvvm_init(); //is called by the registry
};
// myclass.h
class MyClass : public QObject
{
Q_OBJECT
QTMVVM_INJECT_PROP(IService*, service, _service)
public:
Q_INVOKABLE MyClass(QObject *parent = nullptr); //required signature
//...
private:
IService *_service;
};
//main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtMvvm::registerInterfaceConverter<IService>();
QtMvvm::ServiceRegistry::instance()->registerInterface<IService, Service>();
//...
auto myObj = QtMvvm::ServiceRegistry::instance()->constructInjected<MyClass>();
// _service is now initialized via a valid IService
}
@endcode
@sa QtMvvm::registerInterfaceConverter, #QTMVVM_INJECT, #QTMVVM_INJECT_PROP, ViewModel
*/
/*!
@fn QtMvvm::ServiceRegistry::registerInterface(DestructionScope, bool)
@tparam TInterface The interface type to register the service for
@tparam TService The service to be registered for that interface. Must extend QObject and
implement TInterface
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TInterface
If the function returns successfully, from now on a service of the given type can be accessed
via the registry for the interface. The service is lazy initialized an will be created as soon
as it is requested for the first time. If it has any injectable properties, they will be
automatically injected on construction.
If the service is registered as weak, registering another service for the same interface will
not throw an exception but instead discard (and delete) this one.
@attention Make shure to register TInterface via QtMvvm::registerInterfaceConverter, otherwise
injection for the interface is not possible. In addition to this, TService must have an
invokable constructor with the following signature:
`Q_INVOKABLE explicit TService(QObject *parent = nullptr);`
@sa ServiceRegistry::registerPlugin, ServiceRegistry::registerObject,
QtMvvm::registerInterfaceConverter, ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerInterface(TFunc, DestructionScope, bool)
@tparam TInterface The interface type to register the service for
@tparam TService The service to be registered for that interface. Must extend QObject and
implement TInterface
@tparam TFunc The function type of the `fn` parameter.
@param fn The function to be called to construct the service
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TInterface
If the function returns successfully, from now on a service of the given type can be accessed
via the registry for the interface. The service is lazy initialized an will be created as soon
as it is requested for the first time. It is created by calling the given `fn` function.
`fn` must have the following signature:
@code{.cpp}
TService *fn(...);
@endcode
TService is the template parameter of this function. The arguments are variable, but if
arguments are present, they all must be pointers of types that are injectable via the registry.
When the function is called internally, the registry will "inject" all services as parameters
of this function.
If the service is registered as weak, registering another service for the same interface will
not throw an exception but instead discard (and delete) this one.
@attention Make shure to register TInterface via QtMvvm::registerInterfaceConverter, otherwise
injection for the interface is not possible.
@sa ServiceRegistry::registerPlugin, ServiceRegistry::registerObject,
QtMvvm::registerInterfaceConverter, ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerInterface(TService *, DestructionScope, bool)
@tparam TInterface The interface type to register the service for
@tparam TService The service to be registered for that interface. Must extend QObject and
implement TInterface
@param service The service instance to be registered as service
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TInterface
If the function returns successfully, from now on a service of the given type can be accessed
via the registry for the interface. The service instance is from that point on owned by the
registry. No DI is performed on the passed service.
If the service is registered as weak, registering another service for the same interface will
not throw an exception but instead discard (and delete) this one.
@attention Make shure to register TInterface via QtMvvm::registerInterfaceConverter, otherwise
injection for the interface is not possible.
@sa ServiceRegistry::registerPlugin, ServiceRegistry::registerObject,
QtMvvm::registerInterfaceConverter, ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerObject(DestructionScope, bool)
@tparam TService The service to be registered by its own type. Must extend QObject
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TService
If the function returns successfully, from now on a service of the given type can be accessed
via the registry. The service is lazy initialized an will be created as soon
as it is requested for the first time. If it has any injectable properties, they will be
automatically injected on construction.
If the service is registered as weak, registering another service for the same TService will
not throw an exception but instead discard (and delete) this one.
@attention In order to be able to create the service, TService must have an invokable
constructor with the following signature:
`Q_INVOKABLE explicit TService(QObject *parent = nullptr);`
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerPlugin,
ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerObject(TFunc, DestructionScope, bool)
@tparam TService The service to be registered by its own type. Must extend QObject
@tparam TFunc The function type of the `fn` parameter.
@param fn The function to be called to construct the service
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for TService
If the function returns successfully, from now on a service of the given type can be accessed
via the registry. The service is lazy initialized an will be created as soon
as it is requested for the first time. It is created by calling the given `fn` function.
`fn` must have the following signature:
@code{.cpp}
TService *fn(...);
@endcode
TService is the template parameter of this function. The arguments are variable, but if
arguments are present, they all must be pointers of types that are injectable via theregistry.
When the function is called internally, the registry will "inject" all services as parameters
of this function.
If the service is registered as weak, registering another service for the same TService will
not throw an exception but instead discard (and delete) this one.
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerPlugin,
ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerObject(TService *, DestructionScope, bool)
@tparam TService The service to be registered by its own type. Must extend QObject
@param service The service instance to be registered as service
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for TService
If the function returns successfully, from now on a service of the given type can be accessed
via the registry. The service instance is from that point on owned by the registry. No DI is
performed on the passed service.
If the service is registered as weak, registering another service for the same TService will
not throw an exception but instead discard (and delete) this one.
@attention Make shure to register TInterface via QtMvvm::registerInterfaceConverter, otherwise
injection for the interface is not possible.
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerPlugin,
ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerPlugin(QString, QString, DestructionScope, bool)
@tparam TInterface The interface type to register the service for
@param pluginType The kind of plugin to be loaded. Corresponds to the subdirectoy to find the
plugin in
@param pluginKey The key to select the plugin by, if multiple are available
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TInterface
If the function returns successfully, from now on a service of the given type can be accessed
via the registry for the interface. The service is lazy initialized an will be created as soon
as it is requested for the first time. If it has any injectable properties, they will be
automatically injected on construction.
If the service is registered as weak, registering another service for the same interface will
not throw an exception but instead discard (and delete) this one.
To actually create the instance, the registry will try to find a matching plugin to load and
instanciate it. The two parameters, pluginType and pluginKey are used to select a plugin.
pluginType referes to the kind of plugin, i.e. "imageformats", "platforms", ... The value can
either be a relative path, which means it is resolved relative to the standard plugin
directories the application uses to find Qt plugins (pluginType can be empty to directly look
in the root folders). If the path is absolute, only that absolute folder is searched. For both
cases, the search is non-recursive.
pluginKey is a key to select the actual plugin files from all the plugins available in the
folder identified by pluginType. For that, the "Key" property of the metadata of each plugin
is checked to find one that has the given key in the list. If not specified, one of the
available plugins is randomly choosen.
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerObject,
QtMvvm::registerInterfaceConverter, ServiceRegistry::registerService,
ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerService(const QByteArray &, const QMetaObject *, DestructionScope, bool)
@param iid The interface id of the type to register the service for
@param metaObject The metaobject of the service to be registered for that interface. Must
extend QObject and implement the interface of `iid`, unless it is the id of the service itself
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for the iid
If the function returns successfully, from now on a service of the given metobject can be
accessed via the registry for the iid. The service is lazy initialized an will be created as
soon as it is requested for the first time. If it has any injectable properties, they will be
automatically injected on construction.
If the service is registered as weak, registering another service for the same iid will not
throw an exception but instead discard (and delete) this one.
@attention In order to be able to create the service, the class defined by the metaobject must
have an invokable constructor with the following signature:
`Q_INVOKABLE explicit Service(QObject *parent = nullptr);`
@sa QtMvvm::registerInterface, ServiceRegistry::registerObject,
ServiceRegistry::registerPlugin, ServiceRegistry::serviceObj
*/
/*!
@fn QtMvvm::ServiceRegistry::registerService(const QByteArray &, const std::function<QObject*(const QObjectList &)> &, QByteArrayList, DestructionScope, bool)
@param iid The interface id of the type to register the service for
@param fn The function to be called to construct the service
@param injectables The iids of the parameters to be passed to `fn`
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for the iid
If the function returns successfully, from now on a service of the given type can be accessed
via the registry for the interface. The service is lazy initialized an will be created as soon
as it is requested for the first time. It is created by calling the given `fn` function.
The function must return an object that implements the interface of `iid`, unless it is the id
of the service itself. The arguments are passed as object list and are determined by the
`injectables` parameter. That is a list of iids. When the function is called internally, the
registry will "inject" all services found by the iids as parameters of this function, combined
to a list of objects.
If the service is registered as weak, registering another service for the same iid will not
throw an exception but instead discard (and delete) this one.
@sa QtMvvm::registerInterface, ServiceRegistry::registerObject,
ServiceRegistry::registerPlugin, ServiceRegistry::serviceObj
*/
/*!
@fn QtMvvm::ServiceRegistry::registerService(QByteArray, QString, QString, DestructionScope, bool)
@param iid The interface id of the type to register the service for
@param pluginType The kind of plugin to be loaded. Corresponds to the subdirectoy to find the
plugin in
@param pluginKey The key to select the plugin by, if multiple are available
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for the iid
If the function returns successfully, from now on a service of the given type can be accessed
via the registry for the interface. The service is lazy initialized an will be created as soon
as it is requested for the first time. If it has any injectable properties, they will be
automatically injected on construction.
If the service is registered as weak, registering another service for the same interface will
not throw an exception but instead discard (and delete) this one.
To actually create the instance, the registry will try to find a matching plugin to load and
instanciate it. The two parameters, pluginType and pluginKey are used to select a plugin.
pluginType referes to the kind of plugin, i.e. "imageformats", "platforms", ... The value can
either be a relative path, which means it is resolved relative to the standard plugin
directories the application uses to find Qt plugins (pluginType can be empty to directly look
in the root folders). If the path is absolute, only that absolute folder is searched. For both
cases, the search is non-recursive.
pluginKey is a key to select the actual plugin files from all the plugins available in the
folder identified by pluginType. For that, the "Key" property of the metadata of each plugin
is checked to find one that has the given key in the list. If not specified, one of the
available plugins is randomly choosen.
@sa QtMvvm::registerInterface, ServiceRegistry::registerObject,
ServiceRegistry::registerPlugin, ServiceRegistry::serviceObj
*/
/*!
@fn QtMvvm::ServiceRegistry::service
@tparam TInterface The interface type get an instance of
@returns An object that implements the interface
@throws ServiceConstructionException If the registry failed to create an instance for that
interface
If the service is lazy inizialized and not created yet, the registry will do so. The returned
service is owned by the registry. Be careful with weak services, as they may be deleted at any
time. For normal services, this is never the case.
@note TInterface can either be an actual interface or a service type, depending on what you
registered it for (i.e. TInterface of the registerInterface() method and TService of the
registerObject() method
@sa ServiceRegistry::registerObject, QtMvvm::registerInterface, ServiceRegistry::serviceObj,
ServiceRegistry::injectServices, ServiceRegistry::constructInjected
*/
/*!
@fn QtMvvm::ServiceRegistry::serviceObj
@param iid The interface id of the type to get an instance of
@returns An object that implements the interface specified by iid
@throws ServiceConstructionException If the registry failed to create an instance for that
interface
If the service is lazy inizialized and not created yet, the registry will do so. The returned
service is owned by the registry. Be careful with weak services, as they may be deleted at any
time. For normal services, this is never the case.
@note iid must be the identity the service has been registered for. This depends on the type
itself and how it was registered.
@sa ServiceRegistry::registerService, ServiceRegistry::serviceObj,
ServiceRegistry::injectServices, ServiceRegistry::constructInjected
*/
/*!
@fn QtMvvm::ServiceRegistry::injectServices
@param object The object to inject properties into
@throws ServiceConstructionException If the registry failed to create an instance that needs
to be injected into the object
Loads all services that are needed to inject into properties of the object that are marked for
injection via #QTMVVM_INJECT. If any lazy service has not been created yet, it is created on
the fly and then injected.
@sa ServiceRegistry::constructInjected, ServiceRegistry::service, #QTMVVM_INJECT,
#QTMVVM_INJECT_PROP
*/
/*!
@fn QtMvvm::ServiceRegistry::constructInjected(QObject *)
@tparam TClass The type of object to be created, must extend QObject
@param parent The parent object of the created object
@returns A newly created instance of TClass.
@throws ServiceConstructionException If the registry failed to create an instance that needs
to be injected into the object
First the method creates a new instance of TClass, then loads all services that are needed to
inject into properties of the object that are marked for injection via #QTMVVM_INJECT. If any
lazy service has not been created yet, it is created on the fly and then injected. The
returned object is parented to the parent object. If that is null it is owned by the caller.
@attention For this to work, the TClass must have an invokable constructor with the following
signature: `Q_INVOKABLE explicit TClass(QObject *parent = nullptr);`
@sa ServiceRegistry::injectServices, ServiceRegistry::service, #QTMVVM_INJECT,
#QTMVVM_INJECT_PROP
*/
/*!
@fn QtMvvm::ServiceRegistry::constructInjected(const QMetaObject *, QObject *)
@param metaObject The metaobject of object type to be created, must extend QObject
@param parent The parent object of the created object
@returns A newly created instance of the given type.
@throws ServiceConstructionException If the registry failed to create an instance that needs
to be injected into the object
First the method creates a new instance of metaObject, then loads all services that are needed
to inject into properties of the object that are marked for injection via #QTMVVM_INJECT. If
any lazy service has not been created yet, it is created on the fly and then injected. The
returned object is parented to the parent object. If that is null it is owned by the caller.
@attention For this to work, the class defined by metaObject must have an invokable constructor
with the following signature: `Q_INVOKABLE explicit TClass(QObject *parent = nullptr);`
@sa ServiceRegistry::injectServices, ServiceRegistry::service, #QTMVVM_INJECT,
#QTMVVM_INJECT_PROP
*/