diff options
Diffstat (limited to 'lib/private/EventDispatcher')
-rw-r--r-- | lib/private/EventDispatcher/EventDispatcher.php | 89 | ||||
-rw-r--r-- | lib/private/EventDispatcher/ServiceEventListener.php | 59 |
2 files changed, 148 insertions, 0 deletions
diff --git a/lib/private/EventDispatcher/EventDispatcher.php b/lib/private/EventDispatcher/EventDispatcher.php new file mode 100644 index 00000000000..474c902013b --- /dev/null +++ b/lib/private/EventDispatcher/EventDispatcher.php @@ -0,0 +1,89 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\EventDispatcher; + +use OC\Broadcast\Events\BroadcastEvent; +use OC\Log; +use OCP\Broadcast\Events\IBroadcastEvent; +use OCP\EventDispatcher\ABroadcastedEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyDispatcher; +use function get_class; + +class EventDispatcher implements IEventDispatcher { + public function __construct( + private SymfonyDispatcher $dispatcher, + private ContainerInterface $container, + private LoggerInterface $logger, + ) { + // inject the event dispatcher into the logger + // this is done here because there is a cyclic dependency between the event dispatcher and logger + if ($this->logger instanceof Log || $this->logger instanceof Log\PsrLoggerAdapter) { + $this->logger->setEventDispatcher($this); + } + } + + public function addListener(string $eventName, + callable $listener, + int $priority = 0): void { + $this->dispatcher->addListener($eventName, $listener, $priority); + } + + public function removeListener(string $eventName, + callable $listener): void { + $this->dispatcher->removeListener($eventName, $listener); + } + + public function addServiceListener(string $eventName, + string $className, + int $priority = 0): void { + $listener = new ServiceEventListener( + $this->container, + $className, + $this->logger + ); + + $this->addListener($eventName, $listener, $priority); + } + + public function hasListeners(string $eventName): bool { + return $this->dispatcher->hasListeners($eventName); + } + + /** + * @deprecated + */ + public function dispatch(string $eventName, + Event $event): void { + $this->dispatcher->dispatch($event, $eventName); + + if ($event instanceof ABroadcastedEvent && !$event->isPropagationStopped()) { + // Propagate broadcast + $this->dispatch( + IBroadcastEvent::class, + new BroadcastEvent($event) + ); + } + } + + public function dispatchTyped(Event $event): void { + $this->dispatch(get_class($event), $event); + } + + /** + * @return SymfonyDispatcher + * @deprecated 20.0.0 + */ + public function getSymfonyDispatcher(): SymfonyDispatcher { + return $this->dispatcher; + } +} diff --git a/lib/private/EventDispatcher/ServiceEventListener.php b/lib/private/EventDispatcher/ServiceEventListener.php new file mode 100644 index 00000000000..f9cc85b4126 --- /dev/null +++ b/lib/private/EventDispatcher/ServiceEventListener.php @@ -0,0 +1,59 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\EventDispatcher; + +use OCP\AppFramework\QueryException; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use function sprintf; + +/** + * Lazy service event listener + * + * Makes it possible to lazy-route a dispatched event to a service instance + * created by the service container + */ +final class ServiceEventListener { + private ?IEventListener $service = null; + + public function __construct( + private ContainerInterface $container, + private string $class, + private LoggerInterface $logger, + ) { + } + + public function __invoke(Event $event) { + if ($this->service === null) { + try { + // TODO: fetch from the app containers, otherwise any custom services, + // parameters and aliases won't be resolved. + // See https://github.com/nextcloud/server/issues/27793 for details. + $this->service = $this->container->get($this->class); + } catch (QueryException $e) { + $this->logger->error( + sprintf( + 'Could not load event listener service %s: %s. Make sure the class is auto-loadable by the Nextcloud server container', + $this->class, + $e->getMessage() + ), + [ + 'exception' => $e, + ] + ); + return; + } + } + + $this->service->handle($event); + } +} |