.. _Bootstrapping: ============= Bootstrapping ============= Every php process has a relatively short lifespan that lasts as long as the HTTP request or the invocation of the command line program. At the beginning of this lifespan, Nextcloud initializes its services. At the same time, any additional apps might want to register their services to Nextcloud as well. This event is called the *bootstrapping* and this chapter shall shed some light on how to hook into this with an app. .. _application-php: The Application class --------------------- The `Application` class is the main entry point of an app. This class is optional but highly recommended if your app needs to register any services or run some code for every request. Nextcloud will try to autoload the class from the namespace ``\OCA\\AppInfo\Application``, like ``\OCA\MyApp\AppInfo\Application``, where *MyApp* would be the name of your app. The file will therefore have the location ``myapp/lib/AppInfo/Application.php``. .. code-block:: php registerEventListener( BeforeUserDeletedEvent::class, UserDeletedListener::class ); } public function boot(IBootContext $context): void { // ... boot logic goes here ... /** @var IManager $manager */ $manager = $context->getAppContainer()->query(IManager::class); $manager->registerNotifierService(Notifier::class); } } Note that the context objects of the methods ``register`` and ``boot`` have different interfaces and thus have different capabilities appropriate for their stage. Bootstrapping process --------------------- To give a better overview of *when* each of the bootstrapping stages are reached and how they app can interact with them, this section explains the changes done for Nextcloud 20. Nextcloud 20 and later ********************** Nextcloud 20 is the first release with the interface ``\OCP\AppFramework\Bootstrap\IBootstrap``. This interface can be implemented by your app's ``Application`` class to signal that it wants to act on the bootstrapping stages. The major difference between this and the old process is that the bootstrapping is not performed in sequence, but apps register and boot interleaved. This should ensure that an app that ``boot``\s can rely on all other apps' registration to be finished. The overall process is as follows: 1) In each installed and enabled app that has an ``Application`` class that also implements ``IBootstrap``, the ``register`` method will be called. This method receives a context argument via which the app can prime the dependency injection container and register other services lazily, e.g. by calling ``$context->registerService(...)``. The emphasis is on **laziness**. At this very early stage of the process lifetime, no other apps nor all of the server components are ready. Therefore the app **must not** try to use anything except the API provided by the context. That shall ensure that all apps can safely run their registration logic before any services are queried (instantiated) from the DI container or related code is run. 2) Nextcloud will load groups of certain apps early, e.g. filesystem or session apps, and other later. 3) Nextcloud will query the app's ``Application`` class (again), no matter whether it implements ``IBootstrap`` or not. 4) Nextcloud will invoke the :ref:`boot ` method of every ``Application`` instance that implements ``IBootstrap``. At this stage you may assume that all registrations via ``IBootstrap::register`` have completed. .. _app-bootstrap-boot: Booting an app ^^^^^^^^^^^^^^ Any code that should run once for every Nextcloud process goes into the ``boot`` method of an app's ``Application`` class. Use this mechanism carefully as it could have a negative effect on Nextcloud's overall performance. .. code-block:: php :caption: lib/AppInfo/Application.php :emphasize-lines: 11-15 getAppContainer()->query(IFooManager::class); $manager->registerCustomFoo(MyFooImpl::class); } } The code above fetches a fictional *foo manager* to register an app class. The boot context object comes with a ``injectFn`` helper that eases dependency injection inside the ``boot`` method by injecting arguments of a callable: .. code-block:: php :caption: lib/AppInfo/Application.php :emphasize-lines: 12-14 injectFn(function(IFooManager $manager) { $manager->registerCustomFoo(MyFooImpl::class); }); } } With the help of ``Closure::fromCallable`` you can also delegate to other methods that get their arguments injected: .. code-block:: php :caption: lib/AppInfo/Application.php :emphasize-lines: 12,15-17 injectFn($this->registerFoo(...)); } protected function registerFoo(IFooManager $manager): void { $manager->registerCustomFoo(MyFooImpl::class); } }