From 69571fb536c7ad231ea4e5d350f8112a5923c6e1 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Thu, 7 May 2020 21:10:30 +0200 Subject: [PATCH 1/6] Add dedicated API for apps' bootstrapping process Signed-off-by: Christoph Wurst --- .../lib/AppInfo/Application.php | 1 - lib/base.php | 4 + lib/composer/composer/autoload_classmap.php | 6 + lib/composer/composer/autoload_static.php | 6 + .../AppFramework/Bootstrap/BootContext.php | 48 +++ .../AppFramework/Bootstrap/Coordinator.php | 130 ++++++++ .../Bootstrap/RegistrationContext.php | 295 ++++++++++++++++++ lib/private/legacy/OC_App.php | 3 + .../AppFramework/Bootstrap/IBootContext.php | 55 ++++ .../AppFramework/Bootstrap/IBootstrap.php | 46 +++ .../Bootstrap/IRegistrationContext.php | 108 +++++++ .../Bootstrap/BootContextTest.php | 67 ++++ .../Bootstrap/CoordinatorTest.php | 116 +++++++ .../Bootstrap/RegistrationContextTest.php | 162 ++++++++++ 14 files changed, 1046 insertions(+), 1 deletion(-) create mode 100644 lib/private/AppFramework/Bootstrap/BootContext.php create mode 100644 lib/private/AppFramework/Bootstrap/Coordinator.php create mode 100644 lib/private/AppFramework/Bootstrap/RegistrationContext.php create mode 100644 lib/public/AppFramework/Bootstrap/IBootContext.php create mode 100644 lib/public/AppFramework/Bootstrap/IBootstrap.php create mode 100644 lib/public/AppFramework/Bootstrap/IRegistrationContext.php create mode 100644 tests/lib/AppFramework/Bootstrap/BootContextTest.php create mode 100644 tests/lib/AppFramework/Bootstrap/CoordinatorTest.php create mode 100644 tests/lib/AppFramework/Bootstrap/RegistrationContextTest.php diff --git a/apps/twofactor_backupcodes/lib/AppInfo/Application.php b/apps/twofactor_backupcodes/lib/AppInfo/Application.php index 4c5d852f95..3cf05073ec 100644 --- a/apps/twofactor_backupcodes/lib/AppInfo/Application.php +++ b/apps/twofactor_backupcodes/lib/AppInfo/Application.php @@ -35,7 +35,6 @@ use OCA\TwoFactorBackupCodes\Listener\RegistryUpdater; use OCA\TwoFactorBackupCodes\Notifications\Notifier; use OCP\AppFramework\App; use OCP\Authentication\TwoFactorAuth\IRegistry; -use OCP\EventDispatcher\IEventDispatcher; use OCP\Notification\IManager; use OCP\Util; diff --git a/lib/base.php b/lib/base.php index 3ac6d978e4..ab199c0972 100644 --- a/lib/base.php +++ b/lib/base.php @@ -644,6 +644,10 @@ class OC { OC\Log\ErrorHandler::register($debug); } + /** @var \OC\AppFramework\Bootstrap\Coordinator $bootstrapCoordinator */ + $bootstrapCoordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class); + $bootstrapCoordinator->runRegistration(); + \OC::$server->getEventLogger()->start('init_session', 'Initialize session'); OC_App::loadApps(['session']); if (!self::$CLI) { diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 930a14df5d..09defdc5ae 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -23,6 +23,9 @@ return array( 'OCP\\AppFramework\\ApiController' => $baseDir . '/lib/public/AppFramework/ApiController.php', 'OCP\\AppFramework\\App' => $baseDir . '/lib/public/AppFramework/App.php', 'OCP\\AppFramework\\AuthPublicShareController' => $baseDir . '/lib/public/AppFramework/AuthPublicShareController.php', + 'OCP\\AppFramework\\Bootstrap\\IBootContext' => $baseDir . '/lib/public/AppFramework/Bootstrap/IBootContext.php', + 'OCP\\AppFramework\\Bootstrap\\IBootstrap' => $baseDir . '/lib/public/AppFramework/Bootstrap/IBootstrap.php', + 'OCP\\AppFramework\\Bootstrap\\IRegistrationContext' => $baseDir . '/lib/public/AppFramework/Bootstrap/IRegistrationContext.php', 'OCP\\AppFramework\\Controller' => $baseDir . '/lib/public/AppFramework/Controller.php', 'OCP\\AppFramework\\Db\\DoesNotExistException' => $baseDir . '/lib/public/AppFramework/Db/DoesNotExistException.php', 'OCP\\AppFramework\\Db\\Entity' => $baseDir . '/lib/public/AppFramework/Db/Entity.php', @@ -538,6 +541,9 @@ return array( 'OC\\AllConfig' => $baseDir . '/lib/private/AllConfig.php', 'OC\\AppConfig' => $baseDir . '/lib/private/AppConfig.php', 'OC\\AppFramework\\App' => $baseDir . '/lib/private/AppFramework/App.php', + 'OC\\AppFramework\\Bootstrap\\BootContext' => $baseDir . '/lib/private/AppFramework/Bootstrap/BootContext.php', + 'OC\\AppFramework\\Bootstrap\\Coordinator' => $baseDir . '/lib/private/AppFramework/Bootstrap/Coordinator.php', + 'OC\\AppFramework\\Bootstrap\\RegistrationContext' => $baseDir . '/lib/private/AppFramework/Bootstrap/RegistrationContext.php', 'OC\\AppFramework\\DependencyInjection\\DIContainer' => $baseDir . '/lib/private/AppFramework/DependencyInjection/DIContainer.php', 'OC\\AppFramework\\Http' => $baseDir . '/lib/private/AppFramework/Http.php', 'OC\\AppFramework\\Http\\Dispatcher' => $baseDir . '/lib/private/AppFramework/Http/Dispatcher.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 9539dbc1a4..ef34b902cf 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -52,6 +52,9 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\AppFramework\\ApiController' => __DIR__ . '/../../..' . '/lib/public/AppFramework/ApiController.php', 'OCP\\AppFramework\\App' => __DIR__ . '/../../..' . '/lib/public/AppFramework/App.php', 'OCP\\AppFramework\\AuthPublicShareController' => __DIR__ . '/../../..' . '/lib/public/AppFramework/AuthPublicShareController.php', + 'OCP\\AppFramework\\Bootstrap\\IBootContext' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Bootstrap/IBootContext.php', + 'OCP\\AppFramework\\Bootstrap\\IBootstrap' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Bootstrap/IBootstrap.php', + 'OCP\\AppFramework\\Bootstrap\\IRegistrationContext' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Bootstrap/IRegistrationContext.php', 'OCP\\AppFramework\\Controller' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Controller.php', 'OCP\\AppFramework\\Db\\DoesNotExistException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/DoesNotExistException.php', 'OCP\\AppFramework\\Db\\Entity' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/Entity.php', @@ -567,6 +570,9 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\AllConfig' => __DIR__ . '/../../..' . '/lib/private/AllConfig.php', 'OC\\AppConfig' => __DIR__ . '/../../..' . '/lib/private/AppConfig.php', 'OC\\AppFramework\\App' => __DIR__ . '/../../..' . '/lib/private/AppFramework/App.php', + 'OC\\AppFramework\\Bootstrap\\BootContext' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/BootContext.php', + 'OC\\AppFramework\\Bootstrap\\Coordinator' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/Coordinator.php', + 'OC\\AppFramework\\Bootstrap\\RegistrationContext' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/RegistrationContext.php', 'OC\\AppFramework\\DependencyInjection\\DIContainer' => __DIR__ . '/../../..' . '/lib/private/AppFramework/DependencyInjection/DIContainer.php', 'OC\\AppFramework\\Http' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http.php', 'OC\\AppFramework\\Http\\Dispatcher' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Dispatcher.php', diff --git a/lib/private/AppFramework/Bootstrap/BootContext.php b/lib/private/AppFramework/Bootstrap/BootContext.php new file mode 100644 index 0000000000..3831fe4e39 --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/BootContext.php @@ -0,0 +1,48 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OC\AppFramework\Bootstrap; + +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\AppFramework\IAppContainer; +use OCP\IServerContainer; + +class BootContext implements IBootContext { + + /** @var IAppContainer */ + private $appContainer; + + public function __construct(IAppContainer $appContainer) { + $this->appContainer = $appContainer; + } + + public function getAppContainer(): IAppContainer { + return $this->appContainer; + } + + public function getServerContainer(): IServerContainer { + return $this->appContainer->getServer(); + } +} diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php new file mode 100644 index 0000000000..e713ad7ce9 --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/Coordinator.php @@ -0,0 +1,130 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OC\AppFramework\Bootstrap; + +use OC_App; +use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\QueryException; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\ILogger; +use OCP\IServerContainer; +use function class_exists; +use function class_implements; +use function in_array; + +class Coordinator { + + /** @var IServerContainer */ + private $serverContainer; + + /** @var IEventDispatcher */ + private $eventDispatcher; + + /** @var ILogger */ + private $logger; + + public function __construct(IServerContainer $container, + IEventDispatcher $eventListener, + ILogger $logger) { + $this->serverContainer = $container; + $this->eventDispatcher = $eventListener; + $this->logger = $logger; + } + + public function runRegistration(): void { + $context = new RegistrationContext($this->logger); + $apps = []; + foreach (OC_App::getEnabledApps() as $appId) { + /* + * First, we have to enable the app's autoloader + * + * @todo use $this->appManager->getAppPath($appId) here + */ + $path = OC_App::getAppPath($appId); + if ($path === false) { + // Ignore + continue; + } + OC_App::registerAutoloading($appId, $path); + + /* + * Next we check if there is an application class and it implements + * the \OCP\AppFramework\Bootstrap\IBootstrap interface + */ + $appNameSpace = App::buildAppNamespace($appId); + $applicationClassName = $appNameSpace . '\\AppInfo\\Application'; + if (class_exists($applicationClassName) && in_array(IBootstrap::class, class_implements($applicationClassName), true)) { + try { + /** @var IBootstrap|App $application */ + $apps[$appId] = $application = $this->serverContainer->query($applicationClassName); + $application->register($context->for($appId)); + } catch (QueryException $e) { + // Weird, but ok + } + } + } + + /** + * Now that all register methods have been called, we can delegate the registrations + * to the actual services + */ + $context->delegateCapabilityRegistrations($apps); + $context->delegateEventListenerRegistrations($this->eventDispatcher); + $context->delegateContainerRegistrations($apps); + $context->delegateMiddlewareRegistrations($apps); + } + + public function bootApp(string $appId): void { + $appNameSpace = App::buildAppNamespace($appId); + $applicationClassName = $appNameSpace . '\\AppInfo\\Application'; + if (!class_exists($applicationClassName)) { + // Nothing to boot + return; + } + + /* + * Now it is time to fetch an instance of the App class. For classes + * that implement \OCP\AppFramework\Bootstrap\IBootstrap this means + * the instance was already created for register, but any other + * (legacy) code will now do their magic via the constructor. + */ + try { + /** @var App $application */ + $application = $this->serverContainer->query($applicationClassName); + if ($application instanceof IBootstrap) { + /** @var BootContext $context */ + $context = new BootContext($application->getContainer()); + $application->boot($context); + } + } catch (QueryException $e) { + $this->logger->logException($e, [ + 'message' => "Could not boot $appId" . $e->getMessage(), + ]); + return; + } + } +} diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php new file mode 100644 index 0000000000..c7b2290e6b --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -0,0 +1,295 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OC\AppFramework\Bootstrap; + +use Closure; +use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\ILogger; +use Throwable; + +class RegistrationContext { + + /** @var array[] */ + private $capabilities = []; + + /** @var array[] */ + private $services = []; + + /** @var array[] */ + private $aliases = []; + + /** @var array[] */ + private $parameters = []; + + /** @var array[] */ + private $eventListeners = []; + + /** @var array[] */ + private $middlewares = []; + + /** @var ILogger */ + private $logger; + + public function __construct(ILogger $logger) { + $this->logger = $logger; + } + + public function for(string $appId): IRegistrationContext { + return new class($appId, $this) implements IRegistrationContext { + /** @var string */ + private $appId; + + /** @var RegistrationContext */ + private $context; + + public function __construct(string $appId, RegistrationContext $context) { + $this->appId = $appId; + $this->context = $context; + } + + public function registerCapability(string $capability): void { + $this->context->registerCapability( + $this->appId, + $capability + ); + } + + public function registerService(string $name, callable $factory, bool $shared = true): void { + $this->context->registerService( + $this->appId, + $name, + $factory, + $shared + ); + } + + public function registerServiceAlias(string $alias, string $target): void { + $this->context->registerServiceAlias( + $this->appId, + $alias, + $target + ); + } + + public function registerParameter(string $name, $value): void { + $this->context->registerParameter( + $this->appId, + $name, + $value + ); + } + + public function registerEventListener(string $event, string $listener, int $priority = 0): void { + $this->context->registerEventListener( + $this->appId, + $event, + $listener, + $priority + ); + } + + public function registerMiddleware(string $class): void { + $this->context->registerMiddleware( + $this->appId, + $class + ); + } + }; + } + + public function registerCapability(string $appId, string $capability): void { + $this->capabilities[] = [ + 'appId' => $appId, + 'capability' => $capability + ]; + } + + public function registerService(string $appId, string $name, callable $factory, bool $shared = true): void { + $this->services[] = [ + "appId" => $appId, + "name" => $name, + "factory" => $factory, + "sharred" => $shared, + ]; + } + + public function registerServiceAlias(string $appId, string $alias, string $target): void { + $this->aliases[] = [ + "appId" => $appId, + "alias" => $alias, + "target" => $target, + ]; + } + + public function registerParameter(string $appId, string $name, $value): void { + $this->parameters[] = [ + "appId" => $appId, + "name" => $name, + "value" => $value, + ]; + } + + public function registerEventListener(string $appId, string $event, string $listener, int $priority = 0): void { + $this->eventListeners[] = [ + "appId" => $appId, + "event" => $event, + "listener" => $listener, + "priority" => $priority, + ]; + } + + public function registerMiddleware(string $appId, string $class): void { + $this->middlewares[] = [ + "appId" => $appId, + "class" => $class, + ]; + } + + /** + * @param App[] $apps + */ + public function delegateCapabilityRegistrations(array $apps): void { + foreach ($this->capabilities as $registration) { + try { + $apps[$registration['appId']] + ->getContainer() + ->registerCapability($registration['capability']); + } catch (Throwable $e) { + $appId = $registration['appId']; + $this->logger->logException($e, [ + 'message' => "Error during capability registration of $appId: " . $e->getMessage(), + 'level' => ILogger::ERROR, + ]); + } + } + } + + public function delegateEventListenerRegistrations(IEventDispatcher $eventDispatcher): void { + foreach ($this->eventListeners as $registration) { + try { + if (isset($registration['priority'])) { + $eventDispatcher->addServiceListener( + $registration['event'], + $registration['listener'], + $registration['priority'] + ); + } else { + $eventDispatcher->addListener( + $registration['event'], + $registration['listener'] + ); + } + } catch (Throwable $e) { + $appId = $registration['appId']; + $this->logger->logException($e, [ + 'message' => "Error during event listener registration of $appId: " . $e->getMessage(), + 'level' => ILogger::ERROR, + ]); + } + } + } + + /** + * @param App[] $apps + */ + public function delegateContainerRegistrations(array $apps): void { + foreach ($this->services as $registration) { + try { + /** + * Register the service and convert the callable into a \Closure if necessary + */ + $apps[$registration['appId']] + ->getContainer() + ->registerService( + $registration['name'], + Closure::fromCallable($registration['factory']), + $registration['shared'] ?? true + ); + } catch (Throwable $e) { + $appId = $registration['appId']; + $this->logger->logException($e, [ + 'message' => "Error during service registration of $appId: " . $e->getMessage(), + 'level' => ILogger::ERROR, + ]); + } + } + + foreach ($this->aliases as $registration) { + try { + $apps[$registration['appId']] + ->getContainer() + ->registerAlias( + $registration['alias'], + $registration['target'] + ); + } catch (Throwable $e) { + $appId = $registration['appId']; + $this->logger->logException($e, [ + 'message' => "Error during service alias registration of $appId: " . $e->getMessage(), + 'level' => ILogger::ERROR, + ]); + } + } + + foreach ($this->parameters as $registration) { + try { + $apps[$registration['appId']] + ->getContainer() + ->registerParameter( + $registration['name'], + $registration['value'] + ); + } catch (Throwable $e) { + $appId = $registration['appId']; + $this->logger->logException($e, [ + 'message' => "Error during service alias registration of $appId: " . $e->getMessage(), + 'level' => ILogger::ERROR, + ]); + } + } + } + + /** + * @param App[] $apps + */ + public function delegateMiddlewareRegistrations(array $apps): void { + foreach ($this->middlewares as $middleware) { + try { + $apps[$middleware['appId']] + ->getContainer() + ->registerMiddleWare($middleware['class']); + } catch (Throwable $e) { + $appId = $middleware['appId']; + $this->logger->logException($e, [ + 'message' => "Error during capability registration of $appId: " . $e->getMessage(), + 'level' => ILogger::ERROR, + ]); + } + } + } +} diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index dfeac41497..a3c429c9ce 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -149,6 +149,9 @@ class OC_App { // in case someone calls loadApp() directly self::registerAutoloading($app, $appPath); + /** @var \OC\AppFramework\Bootstrap\Coordinator $coordinator */ + $coordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class); + $coordinator->bootApp($app); if (is_file($appPath . '/appinfo/app.php')) { \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app); try { diff --git a/lib/public/AppFramework/Bootstrap/IBootContext.php b/lib/public/AppFramework/Bootstrap/IBootContext.php new file mode 100644 index 0000000000..6ceec5d2fc --- /dev/null +++ b/lib/public/AppFramework/Bootstrap/IBootContext.php @@ -0,0 +1,55 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCP\AppFramework\Bootstrap; + +use OCP\AppFramework\IAppContainer; +use OCP\IServerContainer; + +/** + * @since 20.0.0 + */ +interface IBootContext { + + /** + * Get hold of the app's container + * + * Useful to register and query app-specific services + * + * @return IAppContainer + * @since 20.0.0 + */ + public function getAppContainer(): IAppContainer; + + /** + * Get hold of the server DI container + * + * Useful to register and query system-wide services + * + * @return IServerContainer + * @since 20.0.0 + */ + public function getServerContainer(): IServerContainer; +} diff --git a/lib/public/AppFramework/Bootstrap/IBootstrap.php b/lib/public/AppFramework/Bootstrap/IBootstrap.php new file mode 100644 index 0000000000..581c7d6636 --- /dev/null +++ b/lib/public/AppFramework/Bootstrap/IBootstrap.php @@ -0,0 +1,46 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCP\AppFramework\Bootstrap; + +/** + * @since 20.0.0 + */ +interface IBootstrap { + + /** + * @param IRegistrationContext $context + * + * @since 20.0.0 + */ + public function register(IRegistrationContext $context): void; + + /** + * @param IBootContext $context + * + * @since 20.0.0 + */ + public function boot(IBootContext $context): void; +} diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php new file mode 100644 index 0000000000..589b5def5a --- /dev/null +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -0,0 +1,108 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCP\AppFramework\Bootstrap; + +use OCP\AppFramework\IAppContainer; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\IContainer; + +/** + * The context object passed to IBootstrap::register + * + * @since 20.0.0 + * @see IBootstrap::register() + */ +interface IRegistrationContext { + + /** + * @param string $capability + * @see IAppContainer::registerCapability + * + * @since 20.0.0 + */ + public function registerCapability(string $capability): void; + + /** + * Register a service + * + * @param string $name + * @param callable $factory + * @param bool $shared + * + * @return void + * @see IContainer::registerService() + * + * @since 20.0.0 + */ + public function registerService(string $name, callable $factory, bool $shared = true): void; + + /** + * @param string $alias + * @param string $target + * + * @return void + * @see IContainer::registerAlias() + * + * @since 20.0.0 + */ + public function registerServiceAlias(string $alias, string $target): void; + + /** + * @param string $name + * @param mixed $value + * + * @return void + * @see IContainer::registerParameter() + * + * @since 20.0.0 + */ + public function registerParameter(string $name, $value): void; + + /** + * Register a service listener + * + * This is equivalent to calling IEventDispatcher::addServiceListener + * + * @param string $event preferably the fully-qualified class name of the Event sub class to listen for + * @param string $listener fully qualified class name (or ::class notation) of a \OCP\EventDispatcher\IEventListener that can be built by the DI container + * @param int $priority + * + * @see IEventDispatcher::addServiceListener() + * + * @since 20.0.0 + */ + public function registerEventListener(string $event, string $listener, int $priority = 0): void; + + /** + * @param string $class + * + * @return void + * @see IAppContainer::registerMiddleWare() + * + * @since 20.0.0 + */ + public function registerMiddleware(string $class): void; +} diff --git a/tests/lib/AppFramework/Bootstrap/BootContextTest.php b/tests/lib/AppFramework/Bootstrap/BootContextTest.php new file mode 100644 index 0000000000..219c6d7e78 --- /dev/null +++ b/tests/lib/AppFramework/Bootstrap/BootContextTest.php @@ -0,0 +1,67 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace lib\AppFramework\Bootstrap; + +use OC\AppFramework\Bootstrap\BootContext; +use OCP\AppFramework\IAppContainer; +use OCP\IServerContainer; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class BootContextTest extends TestCase { + + /** @var IAppContainer|MockObject */ + private $appContainer; + + /** @var BootContext */ + private $context; + + protected function setUp(): void { + parent::setUp(); + + $this->appContainer = $this->createMock(IAppContainer::class); + + $this->context = new BootContext( + $this->appContainer + ); + } + + public function testGetAppContainer(): void { + $container = $this->context->getAppContainer(); + + $this->assertSame($this->appContainer, $container); + } + + public function testGetServerContainer(): void { + $serverContainer = $this->createMock(IServerContainer::class); + $this->appContainer->method('getServer') + ->willReturn($serverContainer); + + $container = $this->context->getServerContainer(); + + $this->assertSame($serverContainer, $container); + } +} diff --git a/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php b/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php new file mode 100644 index 0000000000..114872ed54 --- /dev/null +++ b/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php @@ -0,0 +1,116 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace lib\AppFramework\Bootstrap; + +use OC\AppFramework\Bootstrap\Coordinator; +use OCP\App\IAppManager; +use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\AppFramework\QueryException; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\ILogger; +use OCP\IServerContainer; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class CoordinatorTest extends TestCase { + + /** @var IAppManager|MockObject */ + private $appManager; + + /** @var IServerContainer|MockObject */ + private $serverContainer; + + /** @var IEventDispatcher|MockObject */ + private $eventDispatcher; + + /** @var ILogger|MockObject */ + private $logger; + + /** @var Coordinator */ + private $coordinator; + + protected function setUp(): void { + parent::setUp(); + + $this->appManager = $this->createMock(IAppManager::class); + $this->serverContainer = $this->createMock(IServerContainer::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->logger = $this->createMock(ILogger::class); + + $this->coordinator = new Coordinator( + $this->serverContainer, + $this->eventDispatcher, + $this->logger + ); + } + + public function testBootAppNotLoadable(): void { + $appId = 'settings'; + $this->serverContainer->expects($this->once()) + ->method('query') + ->with(\OCA\Settings\AppInfo\Application::class) + ->willThrowException(new QueryException("")); + $this->logger->expects($this->once()) + ->method('logException'); + + $this->coordinator->bootApp($appId); + } + + public function testBootAppNotBootable(): void { + $appId = 'settings'; + $mockApp = $this->createMock(\OCA\Settings\AppInfo\Application::class); + $this->serverContainer->expects($this->once()) + ->method('query') + ->with(\OCA\Settings\AppInfo\Application::class) + ->willReturn($mockApp); + + $this->coordinator->bootApp($appId); + } + + public function testBootApp(): void { + $appId = 'settings'; + $mockApp = new class extends App implements IBootstrap { + public function __construct() { + parent::__construct('test', []); + } + + public function register(IRegistrationContext $context): void { + } + + public function boot(IBootContext $context): void { + } + }; + $this->serverContainer->expects($this->once()) + ->method('query') + ->with(\OCA\Settings\AppInfo\Application::class) + ->willReturn($mockApp); + + $this->coordinator->bootApp($appId); + } +} diff --git a/tests/lib/AppFramework/Bootstrap/RegistrationContextTest.php b/tests/lib/AppFramework/Bootstrap/RegistrationContextTest.php new file mode 100644 index 0000000000..8441b6e983 --- /dev/null +++ b/tests/lib/AppFramework/Bootstrap/RegistrationContextTest.php @@ -0,0 +1,162 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace lib\AppFramework\Bootstrap; + +use OC\AppFramework\Bootstrap\RegistrationContext; +use OCP\AppFramework\App; +use OCP\AppFramework\IAppContainer; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\ILogger; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class RegistrationContextTest extends TestCase { + + /** @var ILogger|MockObject */ + private $logger; + + /** @var RegistrationContext */ + private $context; + + protected function setUp(): void { + parent::setUp(); + + $this->logger = $this->createMock(ILogger::class); + + $this->context = new RegistrationContext( + $this->logger + ); + } + + public function testRegisterCapability(): void { + $app = $this->createMock(App::class); + $name = 'abc'; + $container = $this->createMock(IAppContainer::class); + $app->method('getContainer') + ->willReturn($container); + $container->expects($this->once()) + ->method('registerCapability') + ->with($name); + $this->logger->expects($this->never()) + ->method('logException'); + + $this->context->for('myapp')->registerCapability($name); + $this->context->delegateCapabilityRegistrations([ + 'myapp' => $app, + ]); + } + + public function testRegisterEventListener(): void { + $event = 'abc'; + $service = 'def'; + $dispatcher = $this->createMock(IEventDispatcher::class); + $dispatcher->expects($this->once()) + ->method('addServiceListener') + ->with($event, $service, 0); + $this->logger->expects($this->never()) + ->method('logException'); + + $this->context->for('myapp')->registerEventListener($event, $service); + $this->context->delegateEventListenerRegistrations($dispatcher); + } + + public function testRegisterService(): void { + $app = $this->createMock(App::class); + $service = 'abc'; + $factory = function () { + return 'def'; + }; + $container = $this->createMock(IAppContainer::class); + $app->method('getContainer') + ->willReturn($container); + $container->expects($this->once()) + ->method('registerService') + ->with($service, $factory, true); + $this->logger->expects($this->never()) + ->method('logException'); + + $this->context->for('myapp')->registerService($service, $factory); + $this->context->delegateContainerRegistrations([ + 'myapp' => $app, + ]); + } + + public function testRegisterServiceAlias(): void { + $app = $this->createMock(App::class); + $alias = 'abc'; + $target = 'def'; + $container = $this->createMock(IAppContainer::class); + $app->method('getContainer') + ->willReturn($container); + $container->expects($this->once()) + ->method('registerAlias') + ->with($alias, $target); + $this->logger->expects($this->never()) + ->method('logException'); + + $this->context->for('myapp')->registerServiceAlias($alias, $target); + $this->context->delegateContainerRegistrations([ + 'myapp' => $app, + ]); + } + + public function testRegisterParameter(): void { + $app = $this->createMock(App::class); + $name = 'abc'; + $value = 'def'; + $container = $this->createMock(IAppContainer::class); + $app->method('getContainer') + ->willReturn($container); + $container->expects($this->once()) + ->method('registerParameter') + ->with($name, $value); + $this->logger->expects($this->never()) + ->method('logException'); + + $this->context->for('myapp')->registerParameter($name, $value); + $this->context->delegateContainerRegistrations([ + 'myapp' => $app, + ]); + } + + public function testRegisterMiddleware(): void { + $app = $this->createMock(App::class); + $name = 'abc'; + $container = $this->createMock(IAppContainer::class); + $app->method('getContainer') + ->willReturn($container); + $container->expects($this->once()) + ->method('registerMiddleware') + ->with($name); + $this->logger->expects($this->never()) + ->method('logException'); + + $this->context->for('myapp')->registerMiddleware($name); + $this->context->delegateMiddlewareRegistrations([ + 'myapp' => $app, + ]); + } +} From 0a24d1f8df52a1f719e45538de72f034b1f9ff83 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Fri, 5 Jun 2020 16:17:22 +0200 Subject: [PATCH 2/6] Migrate Comments to the new bootstrap mechanism Signed-off-by: Christoph Wurst --- .../composer/composer/autoload_classmap.php | 1 + .../composer/composer/autoload_static.php | 1 + apps/comments/lib/AppInfo/Application.php | 74 +++++++++---------- .../Listener/CommentsEntityEventListener.php | 44 +++++++++++ 4 files changed, 81 insertions(+), 39 deletions(-) create mode 100644 apps/comments/lib/Listener/CommentsEntityEventListener.php diff --git a/apps/comments/composer/composer/autoload_classmap.php b/apps/comments/composer/composer/autoload_classmap.php index c1cdce7d14..d5d51c7a12 100644 --- a/apps/comments/composer/composer/autoload_classmap.php +++ b/apps/comments/composer/composer/autoload_classmap.php @@ -16,6 +16,7 @@ return array( 'OCA\\Comments\\Controller\\Notifications' => $baseDir . '/../lib/Controller/Notifications.php', 'OCA\\Comments\\EventHandler' => $baseDir . '/../lib/EventHandler.php', 'OCA\\Comments\\JSSettingsHelper' => $baseDir . '/../lib/JSSettingsHelper.php', + 'OCA\\Comments\\Listener\\CommentsEntityEventListener' => $baseDir . '/../lib/Listener/CommentsEntityEventListener.php', 'OCA\\Comments\\Listener\\LoadAdditionalScripts' => $baseDir . '/../lib/Listener/LoadAdditionalScripts.php', 'OCA\\Comments\\Listener\\LoadSidebarScripts' => $baseDir . '/../lib/Listener/LoadSidebarScripts.php', 'OCA\\Comments\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php', diff --git a/apps/comments/composer/composer/autoload_static.php b/apps/comments/composer/composer/autoload_static.php index b38ae5841a..1292415290 100644 --- a/apps/comments/composer/composer/autoload_static.php +++ b/apps/comments/composer/composer/autoload_static.php @@ -31,6 +31,7 @@ class ComposerStaticInitComments 'OCA\\Comments\\Controller\\Notifications' => __DIR__ . '/..' . '/../lib/Controller/Notifications.php', 'OCA\\Comments\\EventHandler' => __DIR__ . '/..' . '/../lib/EventHandler.php', 'OCA\\Comments\\JSSettingsHelper' => __DIR__ . '/..' . '/../lib/JSSettingsHelper.php', + 'OCA\\Comments\\Listener\\CommentsEntityEventListener' => __DIR__ . '/..' . '/../lib/Listener/CommentsEntityEventListener.php', 'OCA\\Comments\\Listener\\LoadAdditionalScripts' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalScripts.php', 'OCA\\Comments\\Listener\\LoadSidebarScripts' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarScripts.php', 'OCA\\Comments\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php', diff --git a/apps/comments/lib/AppInfo/Application.php b/apps/comments/lib/AppInfo/Application.php index 7f3235eb62..8bcf17b2af 100644 --- a/apps/comments/lib/AppInfo/Application.php +++ b/apps/comments/lib/AppInfo/Application.php @@ -31,6 +31,7 @@ use OCA\Comments\Capabilities; use OCA\Comments\Controller\Notifications; use OCA\Comments\EventHandler; use OCA\Comments\JSSettingsHelper; +use OCA\Comments\Listener\CommentsEntityEventListener; use OCA\Comments\Listener\LoadAdditionalScripts; use OCA\Comments\Listener\LoadSidebarScripts; use OCA\Comments\Notification\Notifier; @@ -38,60 +39,55 @@ use OCA\Comments\Search\Provider; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadSidebar; use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\Comments\CommentsEntityEvent; -use OCP\EventDispatcher\IEventDispatcher; +use OCP\IServerContainer; use OCP\Util; -class Application extends App { +class Application extends App implements IBootstrap { public const APP_ID = 'comments'; public function __construct(array $urlParams = []) { parent::__construct(self::APP_ID, $urlParams); - $container = $this->getContainer(); + } - $container->registerAlias('NotificationsController', Notifications::class); + public function register(IRegistrationContext $context): void { + $context->registerCapability(Capabilities::class); - $jsSettingsHelper = new JSSettingsHelper($container->getServer()); + $context->registerServiceAlias('NotificationsController', Notifications::class); + + $context->registerEventListener( + LoadAdditionalScriptsEvent::class, + LoadAdditionalScripts::class + ); + $context->registerEventListener( + LoadSidebar::class, + LoadSidebarScripts::class + ); + $context->registerEventListener( + CommentsEntityEvent::EVENT_ENTITY, + CommentsEntityEventListener::class + ); + } + + public function boot(IBootContext $context): void { + $this->registerNotifier($context->getServerContainer()); + $this->registerCommentsEventHandler($context->getServerContainer()); + + $jsSettingsHelper = new JSSettingsHelper($context->getServerContainer()); Util::connectHook('\OCP\Config', 'js', $jsSettingsHelper, 'extend'); - $this->register(); + $context->getServerContainer()->getSearch()->registerProvider(Provider::class, ['apps' => ['files']]); } - private function register() { - $server = $this->getContainer()->getServer(); - - /** @var IEventDispatcher $newDispatcher */ - $dispatcher = $server->query(IEventDispatcher::class); - - $this->registerEventsScripts($dispatcher); - $this->registerDavEntity($dispatcher); - $this->registerNotifier(); - $this->registerCommentsEventHandler(); - - $this->getContainer()->registerCapability(Capabilities::class); - $server->getSearch()->registerProvider(Provider::class, ['apps' => ['files']]); + protected function registerNotifier(IServerContainer $container) { + $container->getNotificationManager()->registerNotifierService(Notifier::class); } - protected function registerEventsScripts(IEventDispatcher $dispatcher) { - $dispatcher->addServiceListener(LoadAdditionalScriptsEvent::class, LoadAdditionalScripts::class); - $dispatcher->addServiceListener(LoadSidebar::class, LoadSidebarScripts::class); - } - - protected function registerDavEntity(IEventDispatcher $dispatcher) { - $dispatcher->addListener(CommentsEntityEvent::EVENT_ENTITY, function (CommentsEntityEvent $event) { - $event->addEntityCollection('files', function ($name) { - $nodes = \OC::$server->getUserFolder()->getById((int)$name); - return !empty($nodes); - }); - }); - } - - protected function registerNotifier() { - $this->getContainer()->getServer()->getNotificationManager()->registerNotifierService(Notifier::class); - } - - protected function registerCommentsEventHandler() { - $this->getContainer()->getServer()->getCommentsManager()->registerEventHandler(function () { + protected function registerCommentsEventHandler(IServerContainer $container) { + $container->getCommentsManager()->registerEventHandler(function () { return $this->getContainer()->query(EventHandler::class); }); } diff --git a/apps/comments/lib/Listener/CommentsEntityEventListener.php b/apps/comments/lib/Listener/CommentsEntityEventListener.php new file mode 100644 index 0000000000..c08d992405 --- /dev/null +++ b/apps/comments/lib/Listener/CommentsEntityEventListener.php @@ -0,0 +1,44 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCA\Comments\Listener; + +use OCP\Comments\CommentsEntityEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; + +class CommentsEntityEventListener implements IEventListener { + public function handle(Event $event): void { + if (!($event instanceof CommentsEntityEvent)) { + // Unrelated + return; + } + + $event->addEntityCollection('files', function ($name) { + $nodes = \OC::$server->getUserFolder()->getById((int)$name); + return !empty($nodes); + }); + } +} From 0587010dff504eca9320e9039cd76386cc2a208f Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Mon, 8 Jun 2020 18:24:19 +0200 Subject: [PATCH 3/6] Migrate Accessibility app to new bootstrap mechanism Signed-off-by: Christoph Wurst --- apps/accessibility/appinfo/app.php | 37 ----------- .../accessibility/lib/AppInfo/Application.php | 61 +++++++++++++------ .../lib/Migration/RepairUserConfig.php | 8 +-- 3 files changed, 48 insertions(+), 58 deletions(-) delete mode 100644 apps/accessibility/appinfo/app.php diff --git a/apps/accessibility/appinfo/app.php b/apps/accessibility/appinfo/app.php deleted file mode 100644 index b37e726b6c..0000000000 --- a/apps/accessibility/appinfo/app.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * @author Alexey Pyltsyn - * @author John Molakvoæ (skjnldsv) - * @author Robin Appelman - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -use OCA\Accessibility\AppInfo\Application; - -$app = \OC::$server->query(Application::class); - -// Separate from the constructor since the route are not initialized before that -// 1. create the app -// 2. generate css route and inject -$app->injectCss(); -$app->injectJavascript(); diff --git a/apps/accessibility/lib/AppInfo/Application.php b/apps/accessibility/lib/AppInfo/Application.php index 0cac878d34..e691b8353d 100644 --- a/apps/accessibility/lib/AppInfo/Application.php +++ b/apps/accessibility/lib/AppInfo/Application.php @@ -1,4 +1,7 @@ * @@ -27,14 +30,21 @@ namespace OCA\Accessibility\AppInfo; use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\IConfig; +use OCP\IServerContainer; use OCP\IURLGenerator; use OCP\IUserSession; +use function count; +use function implode; +use function md5; -class Application extends App { +class Application extends App implements IBootstrap { /** @var string */ - public const APP_NAME = 'accessibility'; + public const APP_ID = 'accessibility'; /** @var IConfig */ private $config; @@ -46,31 +56,48 @@ class Application extends App { private $urlGenerator; public function __construct() { - parent::__construct(self::APP_NAME); - $this->config = \OC::$server->getConfig(); - $this->userSession = \OC::$server->getUserSession(); - $this->urlGenerator = \OC::$server->getURLGenerator(); + parent::__construct(self::APP_ID); } - public function injectCss() { + public function register(IRegistrationContext $context): void { + } + + public function boot(IBootContext $context): void { + $this->injectCss( + $context->getAppContainer()->query(IUserSession::class), + $context->getAppContainer()->query(IConfig::class), + $context->getAppContainer()->query(IURLGenerator::class) + ); + $this->injectJavascript( + $context->getAppContainer()->query(IURLGenerator::class), + $context->getAppContainer()->query(IConfig::class), + $context->getServerContainer() + ); + } + + private function injectCss(IUserSession $userSession, + IConfig $config, + IURLGenerator $urlGenerator) { // Inject the fake css on all pages if enabled and user is logged - $loggedUser = $this->userSession->getUser(); - if (!is_null($loggedUser)) { - $userValues = $this->config->getUserKeys($loggedUser->getUID(), self::APP_NAME); + $loggedUser = $userSession->getUser(); + if ($loggedUser !== null) { + $userValues = $config->getUserKeys($loggedUser->getUID(), self::APP_ID); // we want to check if any theme or font is enabled. if (count($userValues) > 0) { - $hash = $this->config->getUserValue($loggedUser->getUID(), self::APP_NAME, 'icons-css', md5(implode('-', $userValues))); - $linkToCSS = $this->urlGenerator->linkToRoute(self::APP_NAME . '.accessibility.getCss', ['md5' => $hash]); + $hash = $config->getUserValue($loggedUser->getUID(), self::APP_ID, 'icons-css', md5(implode('-', $userValues))); + $linkToCSS = $urlGenerator->linkToRoute(self::APP_ID . '.accessibility.getCss', ['md5' => $hash]); \OCP\Util::addHeader('link', ['rel' => 'stylesheet', 'href' => $linkToCSS]); } } } - public function injectJavascript() { - $linkToJs = $this->urlGenerator->linkToRoute( - self::APP_NAME . '.accessibility.getJavascript', + private function injectJavascript(IURLGenerator $urlGenerator, + IConfig $config, + IServerContainer $serverContainer) { + $linkToJs = $urlGenerator->linkToRoute( + self::APP_ID . '.accessibility.getJavascript', [ - 'v' => \OC::$server->getConfig()->getAppValue('accessibility', 'cachebuster', '0'), + 'v' => $config->getAppValue(self::APP_ID, 'cachebuster', '0'), ] ); @@ -78,7 +105,7 @@ class Application extends App { 'script', [ 'src' => $linkToJs, - 'nonce' => \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() + 'nonce' => $serverContainer->getContentSecurityPolicyNonceManager()->getNonce() ], '' ); diff --git a/apps/accessibility/lib/Migration/RepairUserConfig.php b/apps/accessibility/lib/Migration/RepairUserConfig.php index 4b946f6a78..2b4bbc1ed1 100644 --- a/apps/accessibility/lib/Migration/RepairUserConfig.php +++ b/apps/accessibility/lib/Migration/RepairUserConfig.php @@ -75,13 +75,13 @@ class RepairUserConfig implements IRepairStep { public function run(IOutput $output) { $output->startProgress(); $this->userManager->callForSeenUsers(function (IUser $user) use ($output) { - $theme = $this->config->getUserValue($user->getUID(), Application::APP_NAME, 'theme', false); + $theme = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'theme', false); if ($theme === 'themedark') { - $this->config->setUserValue($user->getUID(), Application::APP_NAME, 'theme', 'dark'); + $this->config->setUserValue($user->getUID(), Application::APP_ID, 'theme', 'dark'); } if ($theme === 'themehighcontrast') { - $this->config->setUserValue($user->getUID(), Application::APP_NAME, 'highcontrast', 'highcontrast'); - $this->config->deleteUserValue($user->getUID(), Application::APP_NAME, 'theme'); + $this->config->setUserValue($user->getUID(), Application::APP_ID, 'highcontrast', 'highcontrast'); + $this->config->deleteUserValue($user->getUID(), Application::APP_ID, 'theme'); } $output->advance(); }); From 16ab7986b4c019d18bfbfa083ce63040f104ea5b Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Mon, 8 Jun 2020 18:43:16 +0200 Subject: [PATCH 4/6] Migrate Admin Audit app to new bootstrap mechanism Signed-off-by: Christoph Wurst --- apps/admin_audit/appinfo/app.php | 31 ---- apps/admin_audit/lib/AppInfo/Application.php | 160 +++++++++++-------- 2 files changed, 92 insertions(+), 99 deletions(-) delete mode 100644 apps/admin_audit/appinfo/app.php diff --git a/apps/admin_audit/appinfo/app.php b/apps/admin_audit/appinfo/app.php deleted file mode 100644 index aa44f6931d..0000000000 --- a/apps/admin_audit/appinfo/app.php +++ /dev/null @@ -1,31 +0,0 @@ - - * @copyright Copyright (c) 2017 Lukas Reschke - * - * @author Christoph Wurst - * @author Joas Schilling - * @author Lukas Reschke - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -$app = \OC::$server->query(\OCA\AdminAudit\AppInfo\Application::class); -$app->register(); diff --git a/apps/admin_audit/lib/AppInfo/Application.php b/apps/admin_audit/lib/AppInfo/Application.php index 83c392e92e..dde0605103 100644 --- a/apps/admin_audit/lib/AppInfo/Application.php +++ b/apps/admin_audit/lib/AppInfo/Application.php @@ -49,90 +49,110 @@ use OCA\AdminAudit\Actions\UserManagement; use OCA\AdminAudit\Actions\Versions; use OCP\App\ManagerEvent; use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Console\ConsoleEvent; +use OCP\IConfig; use OCP\IGroupManager; use OCP\ILogger; use OCP\IPreview; +use OCP\IServerContainer; use OCP\IUserSession; +use OCP\Log\ILogFactory; use OCP\Share; use OCP\Util; use Symfony\Component\EventDispatcher\GenericEvent; -class Application extends App { +class Application extends App implements IBootstrap { /** @var ILogger */ protected $logger; public function __construct() { parent::__construct('admin_audit'); - $this->initLogger(); } - public function initLogger() { - $c = $this->getContainer()->getServer(); - $config = $c->getConfig(); + public function register(IRegistrationContext $context): void { + } + public function boot(IBootContext $context): void { + $logger = $this->getLogger( + $context->getAppContainer()->query(IConfig::class), + $context->getAppContainer()->query(ILogger::class), + $context->getAppContainer()->query(ILogFactory::class) + ); + + /* + * TODO: once the hooks are migrated to lazy events, this should be done + * in \OCA\AdminAudit\AppInfo\Application::register + */ + $this->registerHooks($logger, $context->getServerContainer()); + } + + private function getLogger(IConfig $config, + ILogger $logger, + ILogFactory $logFactory): ILogger { $default = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/audit.log'; $logFile = $config->getAppValue('admin_audit', 'logfile', $default); - if ($logFile === null) { - $this->logger = $c->getLogger(); - return; - } - $this->logger = $c->getLogFactory()->getCustomLogger($logFile); - } - public function register() { - $this->registerHooks(); + if ($logFile === null) { + return $logger; + } + return $logFactory->getCustomLogger($logFile); } /** * Register hooks in order to log them */ - protected function registerHooks() { - $this->userManagementHooks(); - $this->groupHooks(); - $this->authHooks(); + private function registerHooks(ILogger $logger, + IServerContainer $serverContainer) { + $this->userManagementHooks($logger, $serverContainer); + $this->groupHooks($logger, $serverContainer); + $this->authHooks($logger); - $this->consoleHooks(); - $this->appHooks(); + $this->consoleHooks($logger, $serverContainer); + $this->appHooks($logger, $serverContainer); - $this->sharingHooks(); + $this->sharingHooks($logger); - $this->fileHooks(); - $this->trashbinHooks(); - $this->versionsHooks(); + $this->fileHooks($logger, $serverContainer); + $this->trashbinHooks($logger); + $this->versionsHooks($logger); - $this->securityHooks(); + $this->securityHooks($logger, $serverContainer); } - protected function userManagementHooks() { - $userActions = new UserManagement($this->logger); + private function userManagementHooks(ILogger $logger, + IServerContainer $serverContainer) { + $userActions = new UserManagement($logger); - Util::connectHook('OC_User', 'post_createUser', $userActions, 'create'); - Util::connectHook('OC_User', 'post_deleteUser', $userActions, 'delete'); - Util::connectHook('OC_User', 'changeUser', $userActions, 'change'); + Util::connectHook('OC_User', 'post_createUser', $userActions, 'create'); + Util::connectHook('OC_User', 'post_deleteUser', $userActions, 'delete'); + Util::connectHook('OC_User', 'changeUser', $userActions, 'change'); /** @var IUserSession|Session $userSession */ - $userSession = $this->getContainer()->getServer()->getUserSession(); + $userSession = $serverContainer->getUserSession(); $userSession->listen('\OC\User', 'postSetPassword', [$userActions, 'setPassword']); $userSession->listen('\OC\User', 'assignedUserId', [$userActions, 'assign']); $userSession->listen('\OC\User', 'postUnassignedUserId', [$userActions, 'unassign']); } - protected function groupHooks() { - $groupActions = new GroupManagement($this->logger); + private function groupHooks(ILogger $logger, + IServerContainer $serverContainer) { + $groupActions = new GroupManagement($logger); /** @var IGroupManager|Manager $groupManager */ - $groupManager = $this->getContainer()->getServer()->getGroupManager(); - $groupManager->listen('\OC\Group', 'postRemoveUser', [$groupActions, 'removeUser']); - $groupManager->listen('\OC\Group', 'postAddUser', [$groupActions, 'addUser']); - $groupManager->listen('\OC\Group', 'postDelete', [$groupActions, 'deleteGroup']); - $groupManager->listen('\OC\Group', 'postCreate', [$groupActions, 'createGroup']); + $groupManager = $serverContainer->getGroupManager(); + $groupManager->listen('\OC\Group', 'postRemoveUser', [$groupActions, 'removeUser']); + $groupManager->listen('\OC\Group', 'postAddUser', [$groupActions, 'addUser']); + $groupManager->listen('\OC\Group', 'postDelete', [$groupActions, 'deleteGroup']); + $groupManager->listen('\OC\Group', 'postCreate', [$groupActions, 'createGroup']); } - protected function sharingHooks() { - $shareActions = new Sharing($this->logger); + private function sharingHooks(ILogger $logger) { + $shareActions = new Sharing($logger); Util::connectHook(Share::class, 'post_shared', $shareActions, 'shared'); Util::connectHook(Share::class, 'post_unshare', $shareActions, 'unshare'); @@ -143,41 +163,44 @@ class Application extends App { Util::connectHook(Share::class, 'share_link_access', $shareActions, 'shareAccessed'); } - protected function authHooks() { - $authActions = new Auth($this->logger); + private function authHooks(ILogger $logger) { + $authActions = new Auth($logger); Util::connectHook('OC_User', 'pre_login', $authActions, 'loginAttempt'); Util::connectHook('OC_User', 'post_login', $authActions, 'loginSuccessful'); Util::connectHook('OC_User', 'logout', $authActions, 'logout'); } - protected function appHooks() { - $eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher(); - $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function (ManagerEvent $event) { - $appActions = new AppManagement($this->logger); + private function appHooks(ILogger $logger, + IServerContainer $serverContainer) { + $eventDispatcher = $serverContainer->getEventDispatcher(); + $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function (ManagerEvent $event) use ($logger) { + $appActions = new AppManagement($logger); $appActions->enableApp($event->getAppID()); }); - $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, function (ManagerEvent $event) { - $appActions = new AppManagement($this->logger); + $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, function (ManagerEvent $event) use ($logger) { + $appActions = new AppManagement($logger); $appActions->enableAppForGroups($event->getAppID(), $event->getGroups()); }); - $eventDispatcher->addListener(ManagerEvent::EVENT_APP_DISABLE, function (ManagerEvent $event) { - $appActions = new AppManagement($this->logger); + $eventDispatcher->addListener(ManagerEvent::EVENT_APP_DISABLE, function (ManagerEvent $event) use ($logger) { + $appActions = new AppManagement($logger); $appActions->disableApp($event->getAppID()); }); } - protected function consoleHooks() { - $eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher(); - $eventDispatcher->addListener(ConsoleEvent::EVENT_RUN, function (ConsoleEvent $event) { - $appActions = new Console($this->logger); + private function consoleHooks(ILogger $logger, + IServerContainer $serverContainer) { + $eventDispatcher = $serverContainer->getEventDispatcher(); + $eventDispatcher->addListener(ConsoleEvent::EVENT_RUN, function (ConsoleEvent $event) use ($logger) { + $appActions = new Console($logger); $appActions->runCommand($event->getArguments()); }); } - protected function fileHooks() { - $fileActions = new Files($this->logger); - $eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher(); + private function fileHooks(ILogger $logger, + IServerContainer $serverContainer) { + $fileActions = new Files($logger); + $eventDispatcher = $serverContainer->getEventDispatcher(); $eventDispatcher->addListener( IPreview::EVENT, function (GenericEvent $event) use ($fileActions) { @@ -188,7 +211,7 @@ class Application extends App { 'width' => $event->getArguments()['width'], 'height' => $event->getArguments()['height'], 'crop' => $event->getArguments()['crop'], - 'mode' => $event->getArguments()['mode'] + 'mode' => $event->getArguments()['mode'] ]); } ); @@ -237,26 +260,27 @@ class Application extends App { ); } - protected function versionsHooks() { - $versionsActions = new Versions($this->logger); + private function versionsHooks(ILogger $logger) { + $versionsActions = new Versions($logger); Util::connectHook('\OCP\Versions', 'rollback', $versionsActions, 'rollback'); - Util::connectHook('\OCP\Versions', 'delete',$versionsActions, 'delete'); + Util::connectHook('\OCP\Versions', 'delete', $versionsActions, 'delete'); } - protected function trashbinHooks() { - $trashActions = new Trashbin($this->logger); + private function trashbinHooks(ILogger $logger) { + $trashActions = new Trashbin($logger); Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete'); Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore'); } - protected function securityHooks() { - $eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher(); - $eventDispatcher->addListener(IProvider::EVENT_SUCCESS, function (GenericEvent $event) { - $security = new Security($this->logger); + private function securityHooks(ILogger $logger, + IServerContainer $serverContainer) { + $eventDispatcher = $serverContainer->getEventDispatcher(); + $eventDispatcher->addListener(IProvider::EVENT_SUCCESS, function (GenericEvent $event) use ($logger) { + $security = new Security($logger); $security->twofactorSuccess($event->getSubject(), $event->getArguments()); }); - $eventDispatcher->addListener(IProvider::EVENT_FAILED, function (GenericEvent $event) { - $security = new Security($this->logger); + $eventDispatcher->addListener(IProvider::EVENT_FAILED, function (GenericEvent $event) use ($logger) { + $security = new Security($logger); $security->twofactorFailed($event->getSubject(), $event->getArguments()); }); } From c5d2958ac75302c35dadbfbcc6bf5365740886f5 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Mon, 8 Jun 2020 19:03:46 +0200 Subject: [PATCH 5/6] Migrate Settings to new bootstrap mechanism Signed-off-by: Christoph Wurst --- apps/settings/lib/AppInfo/Application.php | 39 +++++++++++++---------- lib/base.php | 2 -- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/settings/lib/AppInfo/Application.php b/apps/settings/lib/AppInfo/Application.php index 8f70ca426a..27f51a32f1 100644 --- a/apps/settings/lib/AppInfo/Application.php +++ b/apps/settings/lib/AppInfo/Application.php @@ -1,4 +1,7 @@ getContainer(); - + public function register(IRegistrationContext $context): void { // Register Middleware - $container->registerAlias('SubadminMiddleware', SubadminMiddleware::class); - $container->registerMiddleWare('SubadminMiddleware'); + $context->registerServiceAlias('SubadminMiddleware', SubadminMiddleware::class); + $context->registerMiddleware(SubadminMiddleware::class); /** * Core class wrappers */ /** FIXME: Remove once OC_User is non-static and mockable */ - $container->registerService('isAdmin', function () { + $context->registerService('isAdmin', function () { return \OC_User::isAdminUser(\OC_User::getUser()); }); /** FIXME: Remove once OC_SubAdmin is non-static and mockable */ - $container->registerService('isSubAdmin', function (IContainer $c) { + $context->registerService('isSubAdmin', function (IContainer $c) { $userObject = \OC::$server->getUserSession()->getUser(); $isSubAdmin = false; if ($userObject !== null) { @@ -85,20 +91,20 @@ class Application extends App { } return $isSubAdmin; }); - $container->registerService('userCertificateManager', function (IContainer $c) { + $context->registerService('userCertificateManager', function (IContainer $c) { return $c->query('ServerContainer')->getCertificateManager(); }, false); - $container->registerService('systemCertificateManager', function (IContainer $c) { + $context->registerService('systemCertificateManager', function (IContainer $c) { return $c->query('ServerContainer')->getCertificateManager(null); }, false); - $container->registerService(IProvider::class, function (IContainer $c) { + $context->registerService(IProvider::class, function (IContainer $c) { return $c->query('ServerContainer')->query(IProvider::class); }); - $container->registerService(IManager::class, function (IContainer $c) { + $context->registerService(IManager::class, function (IContainer $c) { return $c->query('ServerContainer')->getSettingsManager(); }); - $container->registerService(NewUserMailHelper::class, function (IContainer $c) { + $context->registerService(NewUserMailHelper::class, function (IContainer $c) { /** @var Server $server */ $server = $c->query('ServerContainer'); /** @var Defaults $defaults */ @@ -116,9 +122,12 @@ class Application extends App { Util::getDefaultEmailAddress('no-reply') ); }); + } + public function boot(IBootContext $context): void { /** @var EventDispatcherInterface $eventDispatcher */ - $eventDispatcher = $container->getServer()->getEventDispatcher(); + $eventDispatcher = $context->getServerContainer()->getEventDispatcher(); + $container = $context->getAppContainer(); $eventDispatcher->addListener('app_password_created', function (GenericEvent $event) use ($container) { if (($token = $event->getSubject()) instanceof IToken) { /** @var IActivityManager $activityManager */ @@ -141,13 +150,11 @@ class Application extends App { } } }); - } - public function register() { Util::connectHook('OC_User', 'post_setPassword', $this, 'onChangePassword'); Util::connectHook('OC_User', 'changeUser', $this, 'onChangeInfo'); - $groupManager = $this->getContainer()->getServer()->getGroupManager(); + $groupManager = $context->getServerContainer()->getGroupManager(); $groupManager->listen('\OC\Group', 'postRemoveUser', [$this, 'removeUserFromGroup']); $groupManager->listen('\OC\Group', 'postAddUser', [$this, 'addUserToGroup']); diff --git a/lib/base.php b/lib/base.php index ab199c0972..8109e47cdc 100644 --- a/lib/base.php +++ b/lib/base.php @@ -739,8 +739,6 @@ class OC { // Make sure that the application class is not loaded before the database is setup if ($systemConfig->getValue("installed", false)) { OC_App::loadApp('settings'); - $settings = \OC::$server->query(\OCA\Settings\AppInfo\Application::class); - $settings->register(); } //make sure temporary files are cleaned up From a2c8bfadbc5e5f7d6e2893a2109bc7186d27681d Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Mon, 8 Jun 2020 19:27:28 +0200 Subject: [PATCH 6/6] Migrate Two-Factor Backup Codes to new bootstrap mechanism Signed-off-by: Christoph Wurst --- apps/twofactor_backupcodes/appinfo/app.php | 29 ----------- .../lib/AppInfo/Application.php | 51 ++++++++++--------- 2 files changed, 27 insertions(+), 53 deletions(-) delete mode 100644 apps/twofactor_backupcodes/appinfo/app.php diff --git a/apps/twofactor_backupcodes/appinfo/app.php b/apps/twofactor_backupcodes/appinfo/app.php deleted file mode 100644 index 2ca0108443..0000000000 --- a/apps/twofactor_backupcodes/appinfo/app.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * @author Christoph Wurst - * @author Joas Schilling - * @author Robin Appelman - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -use OCA\TwoFactorBackupCodes\AppInfo\Application; - -$app = \OC::$server->query(Application::class); -$app->register(); diff --git a/apps/twofactor_backupcodes/lib/AppInfo/Application.php b/apps/twofactor_backupcodes/lib/AppInfo/Application.php index 3cf05073ec..1941cb545a 100644 --- a/apps/twofactor_backupcodes/lib/AppInfo/Application.php +++ b/apps/twofactor_backupcodes/lib/AppInfo/Application.php @@ -1,4 +1,7 @@ * @@ -34,44 +37,44 @@ use OCA\TwoFactorBackupCodes\Listener\ProviderEnabled; use OCA\TwoFactorBackupCodes\Listener\RegistryUpdater; use OCA\TwoFactorBackupCodes\Notifications\Notifier; use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\Authentication\TwoFactorAuth\IRegistry; use OCP\Notification\IManager; use OCP\Util; -class Application extends App { +class Application extends App implements IBootstrap { + public const APP_ID = 'twofactor_backupcodes'; + public function __construct() { - parent::__construct('twofactor_backupcodes'); + parent::__construct(self::APP_ID); } - /** - * Register the different app parts - */ - public function register() { - $this->registerHooksAndEvents(); - $this->registerNotification(); + public function register(IRegistrationContext $context): void { + $this->registerHooksAndEvents($context); + } + + public function boot(IBootContext $context): void { + Util::connectHook('OC_User', 'post_deleteUser', $this, 'deleteUser'); + + $this->registerNotification( + $context->getAppContainer()->query(IManager::class) + ); } /** * Register the hooks and events */ - public function registerHooksAndEvents() { - Util::connectHook('OC_User', 'post_deleteUser', $this, 'deleteUser'); - - $container = $this->getContainer(); - - /** @var IEventDispatcher $eventDispatcher */ - $eventDispatcher = $container->query(IEventDispatcher::class); - $eventDispatcher->addServiceListener(CodesGenerated::class, ActivityPublisher::class); - $eventDispatcher->addServiceListener(CodesGenerated::class, RegistryUpdater::class); - $eventDispatcher->addServiceListener(CodesGenerated::class, ClearNotifications::class); - $eventDispatcher->addServiceListener(IRegistry::EVENT_PROVIDER_ENABLED, ProviderEnabled::class); - $eventDispatcher->addServiceListener(IRegistry::EVENT_PROVIDER_DISABLED, ProviderDisabled::class); + public function registerHooksAndEvents(IRegistrationContext $context) { + $context->registerEventListener(CodesGenerated::class, ActivityPublisher::class); + $context->registerEventListener(CodesGenerated::class, RegistryUpdater::class); + $context->registerEventListener(CodesGenerated::class, ClearNotifications::class); + $context->registerEventListener(IRegistry::EVENT_PROVIDER_ENABLED, ProviderEnabled::class); + $context->registerEventListener(IRegistry::EVENT_PROVIDER_DISABLED, ProviderDisabled::class); } - public function registerNotification() { - $container = $this->getContainer(); - /** @var IManager $manager */ - $manager = $container->query(IManager::class); + private function registerNotification(IManager $manager) { $manager->registerNotifierService(Notifier::class); }