From 18369854b784f6456259efbc69284418927c30f1 Mon Sep 17 00:00:00 2001 From: Art4 Date: Sat, 8 Feb 2025 21:59:28 +0000 Subject: [PATCH] Implement route_collection hook as CollectRoutesEvent --- src/App/Router.php | 17 +++-- src/Core/Hooks/HookEventBridge.php | 10 +++ src/Event/CollectRoutesEvent.php | 41 ++++++++++++ tests/Unit/Core/Hooks/HookEventBridgeTest.php | 33 +++++++++ tests/Unit/Event/CollectRoutesEventTest.php | 67 +++++++++++++++++++ 5 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 src/Event/CollectRoutesEvent.php create mode 100644 tests/Unit/Event/CollectRoutesEventTest.php diff --git a/src/App/Router.php b/src/App/Router.php index deb0155cf0..2a8281a855 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -7,12 +7,10 @@ namespace Friendica\App; -use Dice\Dice; use FastRoute\DataGenerator\GroupCountBased; use FastRoute\Dispatcher; use FastRoute\RouteCollector; use FastRoute\RouteParser\Std; -use Friendica\Capabilities\ICanHandleRequests; use Friendica\Core\Addon; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCache; @@ -21,6 +19,7 @@ use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Lock\Capability\ICanLock; use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Event\CollectRoutesEvent; use Friendica\LegacyModule; use Friendica\Module\HTTPException\MethodNotAllowed; use Friendica\Module\HTTPException\PageNotFound; @@ -30,6 +29,7 @@ use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Network\HTTPException\MethodNotAllowedException; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Util\Router\FriendicaGroupCountBased; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Log\LoggerInterface; /** @@ -86,6 +86,8 @@ class Router /** @var LoggerInterface */ private $logger; + private EventDispatcherInterface $eventDispatcher; + /** @var bool */ private $isLocalUser; @@ -110,7 +112,7 @@ class Router * @param IHandleUserSessions $userSession * @param RouteCollector|null $routeCollector */ - public function __construct(array $server, string $baseRoutesFilepath, L10n $l10n, ICanCache $cache, ICanLock $lock, IManageConfigValues $config, Arguments $args, LoggerInterface $logger, IHandleUserSessions $userSession, RouteCollector $routeCollector = null) + public function __construct(array $server, string $baseRoutesFilepath, L10n $l10n, ICanCache $cache, ICanLock $lock, IManageConfigValues $config, Arguments $args, LoggerInterface $logger, EventDispatcherInterface $eventDispatcher, IHandleUserSessions $userSession, RouteCollector $routeCollector = null) { $this->baseRoutesFilepath = $baseRoutesFilepath; $this->l10n = $l10n; @@ -120,6 +122,7 @@ class Router $this->config = $config; $this->server = $server; $this->logger = $logger; + $this->eventDispatcher = $eventDispatcher; $this->isLocalUser = !empty($userSession->getLocalUserId()); $this->routeCollector = $routeCollector ?? new RouteCollector(new Std(), new GroupCountBased()); @@ -147,10 +150,12 @@ class Router $this->addRoutes($routeCollector, $routes); - $this->routeCollector = $routeCollector; - // Add routes from addons - Hook::callAll('route_collection', $this->routeCollector); + $routeCollector = $this->eventDispatcher->dispatch( + new CollectRoutesEvent(CollectRoutesEvent::COLLECT_ROUTES, $routeCollector), + )->getRouteCollector(); + + $this->routeCollector = $routeCollector; return $this; } diff --git a/src/Core/Hooks/HookEventBridge.php b/src/Core/Hooks/HookEventBridge.php index 23cd209e11..1a66b74221 100644 --- a/src/Core/Hooks/HookEventBridge.php +++ b/src/Core/Hooks/HookEventBridge.php @@ -11,6 +11,7 @@ namespace Friendica\Core\Hooks; use Friendica\Core\Hook; use Friendica\Event\ArrayFilterEvent; +use Friendica\Event\CollectRoutesEvent; use Friendica\Event\ConfigLoadedEvent; use Friendica\Event\Event; use Friendica\Event\HtmlFilterEvent; @@ -37,6 +38,7 @@ final class HookEventBridge Event::INIT => 'init_1', Event::HOME_INIT => 'home_init', ConfigLoadedEvent::CONFIG_LOADED => 'load_config', + CollectRoutesEvent::COLLECT_ROUTES => 'route_collection', ArrayFilterEvent::APP_MENU => 'app_menu', ArrayFilterEvent::NAV_INFO => 'nav_info', ArrayFilterEvent::FEATURE_ENABLED => 'isEnabled', @@ -61,6 +63,7 @@ final class HookEventBridge Event::INIT => 'onNamedEvent', Event::HOME_INIT => 'onNamedEvent', ConfigLoadedEvent::CONFIG_LOADED => 'onConfigLoadedEvent', + CollectRoutesEvent::COLLECT_ROUTES => 'onCollectRoutesEvent', ArrayFilterEvent::APP_MENU => 'onArrayFilterEvent', ArrayFilterEvent::NAV_INFO => 'onArrayFilterEvent', ArrayFilterEvent::FEATURE_ENABLED => 'onArrayFilterEvent', @@ -87,6 +90,13 @@ final class HookEventBridge static::callHook($event->getName(), $event->getConfig()); } + public static function onCollectRoutesEvent(CollectRoutesEvent $event): void + { + $event->setRouteCollector( + static::callHook($event->getName(), $event->getRouteCollector()) + ); + } + public static function onArrayFilterEvent(ArrayFilterEvent $event): void { $event->setArray( diff --git a/src/Event/CollectRoutesEvent.php b/src/Event/CollectRoutesEvent.php new file mode 100644 index 0000000000..61e481ba9e --- /dev/null +++ b/src/Event/CollectRoutesEvent.php @@ -0,0 +1,41 @@ +routeCollector = $routeCollector; + } + + public function getRouteCollector(): RouteCollector + { + return $this->routeCollector; + } + + public function setRouteCollector(RouteCollector $routeCollector): void + { + $this->routeCollector = $routeCollector; + } +} diff --git a/tests/Unit/Core/Hooks/HookEventBridgeTest.php b/tests/Unit/Core/Hooks/HookEventBridgeTest.php index adca43d239..688e39ecfa 100644 --- a/tests/Unit/Core/Hooks/HookEventBridgeTest.php +++ b/tests/Unit/Core/Hooks/HookEventBridgeTest.php @@ -9,9 +9,11 @@ declare(strict_types=1); namespace Friendica\Test\Unit\Core\Hooks; +use FastRoute\RouteCollector; use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Hooks\HookEventBridge; use Friendica\Event\ArrayFilterEvent; +use Friendica\Event\CollectRoutesEvent; use Friendica\Event\ConfigLoadedEvent; use Friendica\Event\Event; use Friendica\Event\HtmlFilterEvent; @@ -25,6 +27,7 @@ class HookEventBridgeTest extends TestCase Event::INIT => 'onNamedEvent', Event::HOME_INIT => 'onNamedEvent', ConfigLoadedEvent::CONFIG_LOADED => 'onConfigLoadedEvent', + CollectRoutesEvent::COLLECT_ROUTES => 'onCollectRoutesEvent', ArrayFilterEvent::APP_MENU => 'onArrayFilterEvent', ArrayFilterEvent::NAV_INFO => 'onArrayFilterEvent', ArrayFilterEvent::FEATURE_ENABLED => 'onArrayFilterEvent', @@ -117,6 +120,36 @@ class HookEventBridgeTest extends TestCase HookEventBridge::onConfigLoadedEvent($event); } + public static function getCollectRoutesEventData(): array + { + return [ + ['test', 'test'], + [CollectRoutesEvent::COLLECT_ROUTES, 'route_collection'], + ]; + } + + /** + * @dataProvider getCollectRoutesEventData + */ + public function testOnCollectRoutesEventCallsHookWithCorrectValue($name, $expected): void + { + $routeCollector = $this->createStub(RouteCollector::class); + + $event = new CollectRoutesEvent($name, $routeCollector); + + $reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook'); + $reflectionProperty->setAccessible(true); + + $reflectionProperty->setValue(null, function (string $name, $data) use ($expected, $routeCollector) { + $this->assertSame($expected, $name); + $this->assertSame($routeCollector, $data); + + return $data; + }); + + HookEventBridge::onCollectRoutesEvent($event); + } + public static function getArrayFilterEventData(): array { return [ diff --git a/tests/Unit/Event/CollectRoutesEventTest.php b/tests/Unit/Event/CollectRoutesEventTest.php new file mode 100644 index 0000000000..0a1bb88d59 --- /dev/null +++ b/tests/Unit/Event/CollectRoutesEventTest.php @@ -0,0 +1,67 @@ +createStub(RouteCollector::class)); + + $this->assertInstanceOf(NamedEvent::class, $event); + } + + public static function getPublicConstants(): array + { + return [ + [CollectRoutesEvent::COLLECT_ROUTES, 'friendica.collect_routes'], + ]; + } + + /** + * @dataProvider getPublicConstants + */ + public function testPublicConstantsAreAvailable($value, $expected): void + { + $this->assertSame($expected, $value); + } + + public function testGetNameReturnsName(): void + { + $event = new CollectRoutesEvent('test', $this->createStub(RouteCollector::class)); + + $this->assertSame('test', $event->getName()); + } + + public function testGetRouteCollectorReturnsCorrectString(): void + { + $routeCollector = $this->createStub(RouteCollector::class); + + $event = new CollectRoutesEvent('test', $routeCollector); + + $this->assertSame($routeCollector, $event->getRouteCollector()); + } + + public function testSetRouteCollector(): void + { + $event = new CollectRoutesEvent('test', $this->createStub(RouteCollector::class)); + + $routeCollector = $this->createStub(RouteCollector::class); + + $event->setRouteCollector($routeCollector); + + $this->assertSame($routeCollector, $event->getRouteCollector()); + } +}