/*! @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(); //... 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(); QtMvvm::ServiceRegistry::instance()->registerInterface(); //... auto myObj = QtMvvm::ServiceRegistry::instance()->constructInjected(); // _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 sure 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 sure 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 sure 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 sure 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 &, 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 */