Passing dependencies into the constructor rather than instantiating them in the constructor has the following drawback: Every line in the source code where new AuthorMapper is being used has to be changed, once a new constructor argument is being added to it.

The solution for this particular problem is to limit the new AuthorMapper to one file, the container. The container contains all the factories for creating these objects and is configured in appinfo/application.php.

To add the app’s classes simply open the appinfo/application.php and use the registerService method on the container object:

Now AuthorMapper has all of its dependencies and the object is returned

AuthorService gets the AuthorMapper and returns the object

AuthorController gets the AuthorService and finally the controller can be ``new``ed and the object is returned

So basically the container is used as a giant factory to build all the classes that are needed for the application. Because it centralizes all the creation of objects (the new Class() lines), it is very easy to add new constructor parameters without breaking existing code: only the __construct method and the container line where the new is being called need to be changed.

Automatic assembly creates new instances of classes just by looking at the class name and its constructor parameters. For each constructor parameter the type or the variable name is used to query the container, e.g.:

SomeType $type will use $container->query(‘SomeType’)

$variable will use $container->query(‘variable’)

If all constructor parameters are resolved, the class will be created, saved as a service and returned.

$AppName is resolved because the container registered a parameter under the key ‘AppName’ which will return the app id. The lookup is case sensitive so while $AppName will work correctly, using $appName as a constructor parameter will fail.

If a routes.php file returns an array, and an appname/appinfo/application.php exists, include it, create a new instance of \OCA\AppName\AppInfo\Application.php and register the routes on it. That way a container can be used while still benefitting from the new routes behavior

If a routes.php file returns an array, but there is no appname/appinfo/application.php, create a new \OCP\AppFramework\App instance with the app id and register the routes on it

A request is matched for the route, e.g. with the name page#index

The appropriate container is being queried for the entry PageController (to keep backwards compability)

If the entry does not exist, the container is queried for OCA\AppName\Controller\PageController and if no entry exists, the container tries to create the class by using reflection on its constructor parameters

Interfaces and primitive types can not be instantiated, so the container can not automatically assemble them. The actual implementation needs to be wired up in the container:

<?phpnamespaceOCA\MyApp\AppInfo;classApplicationextends\OCP\AppFramework\App{/** * Define your dependencies in here */publicfunction__construct(array$urlParams=array()){parent::__construct('myapp',$urlParams);$container=$this->getContainer();// AuthorMapper requires a location as string called $TableName$container->registerParameter('TableName','my_app_table');// the interface is called IAuthorMapper and AuthorMapper implements it$container->registerService('OCA\MyApp\Db\IAuthorMapper',function($c){return$c->query('OCA\MyApp\Db\AuthorMapper');});}}

To make use of this new feature, the following things have to be done:

appinfo/info.xml requires to provide another field called namespace where the namespace of the app is defined. The required namespace is the one which comes after the top level namespace OCA\, e.g.: for OCA\MyBeautifulApp\Some\OtherClass the needed namespace would be MyBeautifulApp and would be added to the info.xml in the following way:

In general all of the app’s controllers need to be registered inside the container. Then the following question is: What goes into the constructor of the controller? Pass everything into the controller constructor that matches one of the following criteria:

It does I/O (database, write/read to files)

It is a global (e.g. $_POST, etc. This is in the request class by the way)

The output does not depend on the input variables (also called impure function), e.g. time, random number generator

It is a service, basically it would make sense to swap it out for a different object

What not to inject:

It is pure data and has methods that only act upon it (arrays, data objects)