From aabd73912ec278eb082d7f47d88f350ac523d0c7 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Thu, 28 Jan 2021 14:08:38 +0100 Subject: [PATCH] Type the service registration Signed-off-by: Christoph Wurst --- lib/composer/composer/autoload_classmap.php | 6 + lib/composer/composer/autoload_static.php | 6 + .../AppFramework/Bootstrap/ARegistration.php | 46 +++++ .../Bootstrap/EventListenerRegistration.php | 62 ++++++ .../Bootstrap/ParameterRegistration.php | 57 ++++++ .../Bootstrap/RegistrationContext.php | 179 ++++++++---------- .../Bootstrap/ServiceAliasRegistration.php | 70 +++++++ .../Bootstrap/ServiceFactoryRegistration.php | 72 +++++++ .../Bootstrap/ServiceRegistration.php | 53 ++++++ .../Files/Template/TemplateManager.php | 3 +- lib/private/Http/WellKnown/RequestManager.php | 7 +- lib/private/Search/SearchComposer.php | 3 +- lib/private/legacy/OC_App.php | 6 +- .../Bootstrap/IRegistrationContext.php | 2 + .../lib/Http/WellKnown/RequestManagerTest.php | 13 +- 15 files changed, 468 insertions(+), 117 deletions(-) create mode 100644 lib/private/AppFramework/Bootstrap/ARegistration.php create mode 100644 lib/private/AppFramework/Bootstrap/EventListenerRegistration.php create mode 100644 lib/private/AppFramework/Bootstrap/ParameterRegistration.php create mode 100644 lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php create mode 100644 lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php create mode 100644 lib/private/AppFramework/Bootstrap/ServiceRegistration.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index bf770d48814..c0728ce9f8e 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -584,10 +584,16 @@ 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\\ARegistration' => $baseDir . '/lib/private/AppFramework/Bootstrap/ARegistration.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\\EventListenerRegistration' => $baseDir . '/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php', 'OC\\AppFramework\\Bootstrap\\FunctionInjector' => $baseDir . '/lib/private/AppFramework/Bootstrap/FunctionInjector.php', + 'OC\\AppFramework\\Bootstrap\\ParameterRegistration' => $baseDir . '/lib/private/AppFramework/Bootstrap/ParameterRegistration.php', 'OC\\AppFramework\\Bootstrap\\RegistrationContext' => $baseDir . '/lib/private/AppFramework/Bootstrap/RegistrationContext.php', + 'OC\\AppFramework\\Bootstrap\\ServiceAliasRegistration' => $baseDir . '/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php', + 'OC\\AppFramework\\Bootstrap\\ServiceFactoryRegistration' => $baseDir . '/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php', + 'OC\\AppFramework\\Bootstrap\\ServiceRegistration' => $baseDir . '/lib/private/AppFramework/Bootstrap/ServiceRegistration.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 4fa5b2b282d..f55941501b9 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -613,10 +613,16 @@ 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\\ARegistration' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/ARegistration.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\\EventListenerRegistration' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php', 'OC\\AppFramework\\Bootstrap\\FunctionInjector' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/FunctionInjector.php', + 'OC\\AppFramework\\Bootstrap\\ParameterRegistration' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/ParameterRegistration.php', 'OC\\AppFramework\\Bootstrap\\RegistrationContext' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/RegistrationContext.php', + 'OC\\AppFramework\\Bootstrap\\ServiceAliasRegistration' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php', + 'OC\\AppFramework\\Bootstrap\\ServiceFactoryRegistration' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php', + 'OC\\AppFramework\\Bootstrap\\ServiceRegistration' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/ServiceRegistration.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/ARegistration.php b/lib/private/AppFramework/Bootstrap/ARegistration.php new file mode 100644 index 00000000000..1dde102ca34 --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/ARegistration.php @@ -0,0 +1,46 @@ + + * + * @author 2021 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; + +/** + * @psalm-immutable + */ +abstract class ARegistration { + + /** @var string */ + private $appId; + + public function __construct(string $appId) { + $this->appId = $appId; + } + + /** + * @return string + */ + public function getAppId(): string { + return $this->appId; + } +} diff --git a/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php b/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php new file mode 100644 index 00000000000..17816466970 --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/EventListenerRegistration.php @@ -0,0 +1,62 @@ + + * + * @author 2021 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; + +/** + * @psalm-immutable + * @template-extends ServiceRegistration<\OCP\EventDispatcher\IEventListener> + */ +class EventListenerRegistration extends ServiceRegistration { + + /** @var string */ + private $event; + + /** @var int */ + private $priority; + + public function __construct(string $appId, + string $event, + string $service, + int $priority) { + parent::__construct($appId, $service); + $this->event = $event; + $this->priority = $priority; + } + + /** + * @return string + */ + public function getEvent(): string { + return $this->event; + } + + /** + * @return int + */ + public function getPriority(): int { + return $this->priority; + } +} diff --git a/lib/private/AppFramework/Bootstrap/ParameterRegistration.php b/lib/private/AppFramework/Bootstrap/ParameterRegistration.php new file mode 100644 index 00000000000..2e31d708ee7 --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/ParameterRegistration.php @@ -0,0 +1,57 @@ + + * + * @author 2021 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; + +/** + * @psalm-immutable + */ +final class ParameterRegistration extends ARegistration { + + /** @var string */ + private $name; + + /** @var mixed */ + private $value; + + public function __construct(string $appId, + string $name, + $value) { + parent::__construct($appId); + $this->name = $name; + $this->value = $value; + } + + public function getName(): string { + return $this->name; + } + + /** + * @return mixed + */ + public function getValue() { + return $this->value; + } +} diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index d2dc365d835..619e4f55011 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -34,50 +34,58 @@ use Closure; use OC\Support\CrashReport\Registry; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\AppFramework\Middleware; +use OCP\Authentication\IAlternativeLogin; +use OCP\Capabilities\ICapability; use OCP\Dashboard\IManager; +use OCP\Dashboard\IWidget; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Template\ICustomTemplateProvider; +use OCP\Http\WellKnown\IHandler; use OCP\ILogger; +use OCP\Search\IProvider; +use OCP\Support\CrashReport\IReporter; use Throwable; class RegistrationContext { - /** @var array[] */ + /** @var ServiceRegistration[] */ private $capabilities = []; - /** @var array[] */ + /** @var ServiceRegistration[] */ private $crashReporters = []; - /** @var array[] */ + /** @var ServiceRegistration[] */ private $dashboardPanels = []; - /** @var array[] */ + /** @var ServiceFactoryRegistration[] */ private $services = []; - /** @var array[] */ + /** @var ServiceAliasRegistration[] */ private $aliases = []; - /** @var array[] */ + /** @var ParameterRegistration[] */ private $parameters = []; - /** @var array[] */ + /** @var EventListenerRegistration[] */ private $eventListeners = []; - /** @var array[] */ + /** @var ServiceRegistration[] */ private $middlewares = []; - /** @var array[] */ + /** @var ServiceRegistration[] */ private $searchProviders = []; - /** @var array[] */ + /** @var ServiceRegistration[] */ private $alternativeLogins = []; /** @var array[] */ private $initialStates = []; - /** @var array[] */ + /** @var ServiceRegistration[] */ private $wellKnownHandlers = []; - /** @var array[] */ + /** @var ServiceRegistration[] */ private $templateProviders = []; /** @var ILogger */ @@ -199,80 +207,56 @@ class RegistrationContext { }; } + /** + * @psalm-param class-string $capability + */ public function registerCapability(string $appId, string $capability): void { - $this->capabilities[] = [ - 'appId' => $appId, - 'capability' => $capability - ]; + $this->capabilities[] = new ServiceRegistration($appId, $capability); } + /** + * @psalm-param class-string $capability + */ public function registerCrashReporter(string $appId, string $reporterClass): void { - $this->crashReporters[] = [ - 'appId' => $appId, - 'class' => $reporterClass, - ]; + $this->crashReporters[] = new ServiceRegistration($appId, $reporterClass); } + /** + * @psalm-param class-string $capability + */ public function registerDashboardPanel(string $appId, string $panelClass): void { - $this->dashboardPanels[] = [ - 'appId' => $appId, - 'class' => $panelClass - ]; + $this->dashboardPanels[] = new ServiceRegistration($appId, $panelClass); } public function registerService(string $appId, string $name, callable $factory, bool $shared = true): void { - $this->services[] = [ - "appId" => $appId, - "name" => $name, - "factory" => $factory, - "shared" => $shared, - ]; + $this->services[] = new ServiceFactoryRegistration($appId, $name, $factory, $shared); } public function registerServiceAlias(string $appId, string $alias, string $target): void { - $this->aliases[] = [ - "appId" => $appId, - "alias" => $alias, - "target" => $target, - ]; + $this->aliases[] = new ServiceAliasRegistration($appId, $alias, $target); } public function registerParameter(string $appId, string $name, $value): void { - $this->parameters[] = [ - "appId" => $appId, - "name" => $name, - "value" => $value, - ]; + $this->parameters[] = new ParameterRegistration($appId, $name, $value); } public function registerEventListener(string $appId, string $event, string $listener, int $priority = 0): void { - $this->eventListeners[] = [ - "appId" => $appId, - "event" => $event, - "listener" => $listener, - "priority" => $priority, - ]; + $this->eventListeners[] = new EventListenerRegistration($appId, $event, $listener, $priority); } + /** + * @psalm-param class-string $class + */ public function registerMiddleware(string $appId, string $class): void { - $this->middlewares[] = [ - "appId" => $appId, - "class" => $class, - ]; + $this->middlewares[] = new ServiceRegistration($appId, $class); } public function registerSearchProvider(string $appId, string $class) { - $this->searchProviders[] = [ - 'appId' => $appId, - 'class' => $class, - ]; + $this->searchProviders[] = new ServiceRegistration($appId, $class); } public function registerAlternativeLogin(string $appId, string $class): void { - $this->alternativeLogins[] = [ - 'appId' => $appId, - 'class' => $class, - ]; + $this->alternativeLogins[] = new ServiceRegistration($appId, $class); } public function registerInitialState(string $appId, string $class): void { @@ -283,10 +267,7 @@ class RegistrationContext { } public function registerWellKnown(string $appId, string $class): void { - $this->wellKnownHandlers[] = [ - 'appId' => $appId, - 'class' => $class, - ]; + $this->wellKnownHandlers[] = new ServiceRegistration($appId, $class); } public function registerTemplateProvider(string $appId, string $class): void { @@ -302,11 +283,11 @@ class RegistrationContext { public function delegateCapabilityRegistrations(array $apps): void { while (($registration = array_shift($this->capabilities)) !== null) { try { - $apps[$registration['appId']] + $apps[$registration->getAppId()] ->getContainer() - ->registerCapability($registration['capability']); + ->registerCapability($registration->getService()); } catch (Throwable $e) { - $appId = $registration['appId']; + $appId = $registration->getAppId(); $this->logger->logException($e, [ 'message' => "Error during capability registration of $appId: " . $e->getMessage(), 'level' => ILogger::ERROR, @@ -321,9 +302,9 @@ class RegistrationContext { public function delegateCrashReporterRegistrations(array $apps, Registry $registry): void { while (($registration = array_shift($this->crashReporters)) !== null) { try { - $registry->registerLazy($registration['class']); + $registry->registerLazy($registration->getService()); } catch (Throwable $e) { - $appId = $registration['appId']; + $appId = $registration->getAppId(); $this->logger->logException($e, [ 'message' => "Error during crash reporter registration of $appId: " . $e->getMessage(), 'level' => ILogger::ERROR, @@ -338,9 +319,9 @@ class RegistrationContext { public function delegateDashboardPanelRegistrations(array $apps, IManager $dashboardManager): void { while (($panel = array_shift($this->dashboardPanels)) !== null) { try { - $dashboardManager->lazyRegisterWidget($panel['class']); + $dashboardManager->lazyRegisterWidget($panel->getService()); } catch (Throwable $e) { - $appId = $panel['appId']; + $appId = $panel->getAppId(); $this->logger->logException($e, [ 'message' => "Error during dashboard registration of $appId: " . $e->getMessage(), 'level' => ILogger::ERROR, @@ -352,20 +333,13 @@ class RegistrationContext { public function delegateEventListenerRegistrations(IEventDispatcher $eventDispatcher): void { while (($registration = array_shift($this->eventListeners)) !== null) { try { - if (isset($registration['priority'])) { - $eventDispatcher->addServiceListener( - $registration['event'], - $registration['listener'], - $registration['priority'] - ); - } else { - $eventDispatcher->addServiceListener( - $registration['event'], - $registration['listener'] - ); - } + $eventDispatcher->addServiceListener( + $registration->getEvent(), + $registration->getService(), + $registration->getPriority() + ); } catch (Throwable $e) { - $appId = $registration['appId']; + $appId = $registration->getAppId(); $this->logger->logException($e, [ 'message' => "Error during event listener registration of $appId: " . $e->getMessage(), 'level' => ILogger::ERROR, @@ -383,15 +357,15 @@ class RegistrationContext { /** * Register the service and convert the callable into a \Closure if necessary */ - $apps[$registration['appId']] + $apps[$registration->getAppId()] ->getContainer() ->registerService( - $registration['name'], - Closure::fromCallable($registration['factory']), - $registration['shared'] ?? true + $registration->getName(), + Closure::fromCallable($registration->getFactory()), + $registration->isShared() ); } catch (Throwable $e) { - $appId = $registration['appId']; + $appId = $registration->getAppId(); $this->logger->logException($e, [ 'message' => "Error during service registration of $appId: " . $e->getMessage(), 'level' => ILogger::ERROR, @@ -401,14 +375,14 @@ class RegistrationContext { foreach ($this->aliases as $registration) { try { - $apps[$registration['appId']] + $apps[$registration->getAppId()] ->getContainer() ->registerAlias( - $registration['alias'], - $registration['target'] + $registration->getAlias(), + $registration->getTarget() ); } catch (Throwable $e) { - $appId = $registration['appId']; + $appId = $registration->getAppId(); $this->logger->logException($e, [ 'message' => "Error during service alias registration of $appId: " . $e->getMessage(), 'level' => ILogger::ERROR, @@ -418,14 +392,14 @@ class RegistrationContext { foreach ($this->parameters as $registration) { try { - $apps[$registration['appId']] + $apps[$registration->getAppId()] ->getContainer() ->registerParameter( - $registration['name'], - $registration['value'] + $registration->getName(), + $registration->getValue() ); } catch (Throwable $e) { - $appId = $registration['appId']; + $appId = $registration->getAppId(); $this->logger->logException($e, [ 'message' => "Error during service alias registration of $appId: " . $e->getMessage(), 'level' => ILogger::ERROR, @@ -440,11 +414,11 @@ class RegistrationContext { public function delegateMiddlewareRegistrations(array $apps): void { while (($middleware = array_shift($this->middlewares)) !== null) { try { - $apps[$middleware['appId']] + $apps[$middleware->getAppId()] ->getContainer() - ->registerMiddleWare($middleware['class']); + ->registerMiddleWare($middleware->getService()); } catch (Throwable $e) { - $appId = $middleware['appId']; + $appId = $middleware->getAppId(); $this->logger->logException($e, [ 'message' => "Error during capability registration of $appId: " . $e->getMessage(), 'level' => ILogger::ERROR, @@ -454,14 +428,14 @@ class RegistrationContext { } /** - * @return array[] + * @return ServiceRegistration[] */ public function getSearchProviders(): array { return $this->searchProviders; } /** - * @return array[] + * @return ServiceRegistration[] */ public function getAlternativeLogins(): array { return $this->alternativeLogins; @@ -475,12 +449,15 @@ class RegistrationContext { } /** - * @return array[] + * @return ServiceRegistration[] */ public function getWellKnownHandlers(): array { return $this->wellKnownHandlers; } + /** + * @return ServiceRegistration[] + */ public function getTemplateProviders(): array { return $this->templateProviders; } diff --git a/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php b/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php new file mode 100644 index 00000000000..04823172ed2 --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/ServiceAliasRegistration.php @@ -0,0 +1,70 @@ + + * + * @author 2021 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; + +/** + * @psalm-immutable + */ +class ServiceAliasRegistration extends ARegistration { + + /** + * @var string + * @psalm-var string|class-string + */ + private $alias; + + /** + * @var string + * @psalm-var string|class-string + */ + private $target; + + /** + * @psalm-param string|class-string $alias + * @paslm-param string|class-string $target + */ + public function __construct(string $appId, + string $alias, + string $target) { + parent::__construct($appId); + $this->alias = $alias; + $this->target = $target; + } + + /** + * @psalm-return string|class-string + */ + public function getAlias(): string { + return $this->alias; + } + + /** + * @psalm-return string|class-string + */ + public function getTarget(): string { + return $this->target; + } +} diff --git a/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php b/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php new file mode 100644 index 00000000000..4776c5df55c --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/ServiceFactoryRegistration.php @@ -0,0 +1,72 @@ + + * + * @author 2021 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; + +/** + * @psalm-immutable + */ +class ServiceFactoryRegistration extends ARegistration { + + /** + * @var string + * @psalm-var string|class-string + */ + private $name; + + /** + * @var callable + * @psalm-var callable(\Psr\Container\ContainerInterface): mixed + */ + private $factory; + + /** @var bool */ + private $shared; + + public function __construct(string $appId, + string $alias, + callable $target, + bool $shared) { + parent::__construct($appId); + $this->name = $alias; + $this->factory = $target; + $this->shared = $shared; + } + + public function getName(): string { + return $this->name; + } + + /** + * @psalm-return callable(\Psr\Container\ContainerInterface): mixed + */ + public function getFactory(): callable { + return $this->factory; + } + + public function isShared(): bool { + return $this->shared; + } +} diff --git a/lib/private/AppFramework/Bootstrap/ServiceRegistration.php b/lib/private/AppFramework/Bootstrap/ServiceRegistration.php new file mode 100644 index 00000000000..83ffe01e6c3 --- /dev/null +++ b/lib/private/AppFramework/Bootstrap/ServiceRegistration.php @@ -0,0 +1,53 @@ + + * + * @author 2021 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; + +/** + * @psalm-immutable + * @template T + */ +class ServiceRegistration extends ARegistration { + /** + * @var string + * @psalm-var class-string + */ + private $service; + + /** + * @psalm-param class-string $service + */ + public function __construct(string $appId, string $service) { + parent::__construct($appId); + $this->service = $service; + } + + /** + * @psalm-return class-string + */ + public function getService(): string { + return $this->service; + } +} diff --git a/lib/private/Files/Template/TemplateManager.php b/lib/private/Files/Template/TemplateManager.php index 44e1b10fa35..33d42bc9c42 100644 --- a/lib/private/Files/Template/TemplateManager.php +++ b/lib/private/Files/Template/TemplateManager.php @@ -109,7 +109,8 @@ class TemplateManager implements ITemplateManager { $this->providers = []; foreach ($context->getTemplateProviders() as $provider) { - $this->providers[$provider['class']] = $this->serverContainer->get($provider['class']); + $class = $provider->getService(); + $this->providers[$class] = $this->serverContainer->get($class); } return $this->providers; } diff --git a/lib/private/Http/WellKnown/RequestManager.php b/lib/private/Http/WellKnown/RequestManager.php index 5993a9b36e0..052e2d38ea7 100644 --- a/lib/private/Http/WellKnown/RequestManager.php +++ b/lib/private/Http/WellKnown/RequestManager.php @@ -27,6 +27,7 @@ declare(strict_types=1); namespace OC\Http\WellKnown; use OC\AppFramework\Bootstrap\Coordinator; +use OC\AppFramework\Bootstrap\ServiceRegistration; use OCP\AppFramework\QueryException; use OCP\Http\WellKnown\IHandler; use OCP\Http\WellKnown\IRequestContext; @@ -99,8 +100,9 @@ class RequestManager { $this->logger->debug(count($registrations) . " well known handlers registered"); return array_filter( - array_map(function (array $registration) { - $class = $registration['class']; + array_map(function (ServiceRegistration $registration) { + /** @var ServiceRegistration $registration */ + $class = $registration->getService(); try { $handler = $this->container->get($class); @@ -115,6 +117,7 @@ class RequestManager { } catch (QueryException $e) { $this->logger->error("Could not load well known handler $class", [ 'exception' => $e, + 'app' => $registration->getAppId(), ]); return null; diff --git a/lib/private/Search/SearchComposer.php b/lib/private/Search/SearchComposer.php index 5290c2ac3c1..09355f3aa0e 100644 --- a/lib/private/Search/SearchComposer.php +++ b/lib/private/Search/SearchComposer.php @@ -96,13 +96,14 @@ class SearchComposer { foreach ($registrations as $registration) { try { /** @var IProvider $provider */ - $provider = $this->container->query($registration['class']); + $provider = $this->container->query($registration->getService()); $this->providers[$provider->getId()] = $provider; } catch (QueryException $e) { // Log an continue. We can be fault tolerant here. $this->logger->logException($e, [ 'message' => 'Could not load search provider dynamically: ' . $e->getMessage(), 'level' => ILogger::ERROR, + 'app' => $registration->getAppId(), ]); } } diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index a64b13f1e2c..530291002bb 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -698,11 +698,11 @@ class OC_App { $bootstrapCoordinator = \OC::$server->query(Coordinator::class); foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) { - if (!in_array(IAlternativeLogin::class, class_implements($registration['class']), true)) { + if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) { \OC::$server->getLogger()->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [ - 'option' => $registration['class'], + 'option' => $registration->getService(), 'interface' => IAlternativeLogin::class, - 'app' => $registration['app'], + 'app' => $registration->getAppId(), ]); continue; } diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index 8bc21a545f6..a53a4d2a6e4 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -30,6 +30,7 @@ declare(strict_types=1); namespace OCP\AppFramework\Bootstrap; use OCP\AppFramework\IAppContainer; +use OCP\Capabilities\ICapability; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Template\ICustomTemplateProvider; use OCP\IContainer; @@ -44,6 +45,7 @@ interface IRegistrationContext { /** * @param string $capability + * @psalm-param class-string $capability * @see IAppContainer::registerCapability * * @since 20.0.0 diff --git a/tests/lib/Http/WellKnown/RequestManagerTest.php b/tests/lib/Http/WellKnown/RequestManagerTest.php index b947df49496..1fa92804cfa 100644 --- a/tests/lib/Http/WellKnown/RequestManagerTest.php +++ b/tests/lib/Http/WellKnown/RequestManagerTest.php @@ -27,6 +27,7 @@ namespace Test\Http\WellKnown; use OC\AppFramework\Bootstrap\Coordinator; use OC\AppFramework\Bootstrap\RegistrationContext; +use OC\AppFramework\Bootstrap\ServiceRegistration; use OC\Http\WellKnown\RequestManager; use OCP\AppFramework\QueryException; use OCP\Http\WellKnown\IHandler; @@ -102,9 +103,7 @@ class RequestManagerTest extends TestCase { $registrationContext->expects(self::once()) ->method('getWellKnownHandlers') ->willReturn([ - [ - 'class' => get_class($handler), - ], + new ServiceRegistration('test', get_class($handler)), ]); $this->container->expects(self::once()) ->method('get') @@ -129,9 +128,7 @@ class RequestManagerTest extends TestCase { $registrationContext->expects(self::once()) ->method('getWellKnownHandlers') ->willReturn([ - [ - 'class' => get_class($handler), - ], + new ServiceRegistration('test', get_class($handler)), ]); $this->container->expects(self::once()) ->method('get') @@ -159,9 +156,7 @@ class RequestManagerTest extends TestCase { $registrationContext->expects(self::once()) ->method('getWellKnownHandlers') ->willReturn([ - [ - 'class' => get_class($handler), - ], + new ServiceRegistration('test', get_class($handler)), ]); $this->container->expects(self::once()) ->method('get') -- 2.39.5