diff --git a/composer.json b/composer.json index 89c8a9f41d..ce332415b6 100644 --- a/composer.json +++ b/composer.json @@ -71,9 +71,11 @@ "pragmarx/recovery": "^0.2", "psr/clock": "^1.0", "psr/container": "^2.0", + "psr/event-dispatcher": "^1.0", "psr/log": "^1.1", "seld/cli-prompt": "^1.0", "smarty/smarty": "^4", + "symfony/event-dispatcher": "^5.4", "textalk/websocket": "^1.6", "ua-parser/uap-php": "^3.9", "xemlock/htmlpurifier-html5": "^0.1.11" diff --git a/composer.lock b/composer.lock index 11cc407661..3086ed7be9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "64436f375561718bb857e3e1b0e503c9", + "content-hash": "8ee8f9186d271b65b83c2ddbd12c5c03", "packages": [ { "name": "asika/simple-console", @@ -3234,6 +3234,56 @@ ], "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, { "name": "psr/http-client", "version": "1.0.3", @@ -3709,6 +3759,170 @@ ], "time": "2022-01-02T09:53:40+00:00" }, + { + "name": "symfony/event-dispatcher", + "version": "v5.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "72982eb416f61003e9bb6e91f8b3213600dcf9e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/72982eb416f61003e9bb6e91f8b3213600dcf9e9", + "reference": "72982eb416f61003e9bb6e91f8b3213600dcf9e9", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f", + "reference": "e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "2.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, { "name": "symfony/polyfill-php56", "version": "v1.20.0", @@ -3774,6 +3988,86 @@ ], "time": "2020-10-23T14:02:19+00:00" }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "textalk/websocket", "version": "1.6.3", diff --git a/src/App.php b/src/App.php index 5623f9a413..ace4011720 100644 --- a/src/App.php +++ b/src/App.php @@ -23,10 +23,6 @@ use Friendica\Core\Container; use Friendica\Core\Logger\LoggerManager; use Friendica\Core\Renderer; use Friendica\Core\Session\Capability\IHandleUserSessions; -use Friendica\Database\Definition\DbaDefinition; -use Friendica\Database\Definition\ViewDefinition; -use Friendica\Module\Maintenance; -use Friendica\Security\Authentication; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\DiceContainer; use Friendica\Core\L10n; @@ -35,9 +31,15 @@ use Friendica\Core\Logger\Handler\ErrorHandler; use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues; use Friendica\Core\System; use Friendica\Core\Update; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Database\Definition\ViewDefinition; +use Friendica\Event\Event; +use Friendica\EventSubscriber\HookEventBridge; +use Friendica\Module\Maintenance; use Friendica\Module\Special\HTTPException as ModuleHTTPException; use Friendica\Network\HTTPException; use Friendica\Protocol\ATProtocol\DID; +use Friendica\Security\Authentication; use Friendica\Security\ExAuth; use Friendica\Security\OpenWebAuth; use Friendica\Util\BasePath; @@ -45,6 +47,7 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\HTTPInputData; use Friendica\Util\HTTPSignature; use Friendica\Util\Profiler; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; @@ -153,6 +156,8 @@ class App $this->registerErrorHandler(); + $this->registerEventDispatcher(); + $this->requestId = $this->container->create(Request::class)->getRequestId(); $this->auth = $this->container->create(Authentication::class); $this->config = $this->container->create(IManageConfigValues::class); @@ -178,6 +183,7 @@ class App $this->registerTemplateEngine(); $this->runFrontend( + $this->container->create(EventDispatcherInterface::class), $this->container->create(IManagePersonalConfigValues::class), $this->container->create(Page::class), $this->container->create(Nav::class), @@ -202,6 +208,8 @@ class App $this->registerErrorHandler(); + $this->registerEventDispatcher(); + $this->load( $serverParams, $this->container->create(DbaDefinition::class), @@ -230,6 +238,8 @@ class App $this->registerErrorHandler(); + $this->registerEventDispatcher(); + $this->load( $serverParams, $this->container->create(DbaDefinition::class), @@ -301,6 +311,16 @@ class App ErrorHandler::register($this->container->create(LoggerInterface::class)); } + private function registerEventDispatcher(): void + { + /** @var \Friendica\Event\EventDispatcher */ + $eventDispatcher = $this->container->create(EventDispatcherInterface::class); + + foreach (HookEventBridge::getStaticSubscribedEvents() as $eventName => $methodName) { + $eventDispatcher->addListener($eventName, [HookEventBridge::class, $methodName]); + } + } + private function registerTemplateEngine(): void { Renderer::registerTemplateEngine('Friendica\Render\FriendicaSmartyEngine'); @@ -385,6 +405,7 @@ class App * @throws \ImagickException */ private function runFrontend( + EventDispatcherInterface $eventDispatcher, IManagePersonalConfigValues $pconfig, Page $page, Nav $nav, @@ -424,7 +445,8 @@ class App $serverVars['REQUEST_METHOD'] === 'GET') { System::externalRedirect($this->baseURL . '/' . $this->args->getQueryString()); } - Core\Hook::callAll('init_1'); + + $eventDispatcher->dispatch(new Event(Event::INIT)); } DID::routeRequest($this->args->getCommand(), $serverVars); diff --git a/src/App/Page.php b/src/App/Page.php index ca83173184..b5a00859f1 100644 --- a/src/App/Page.php +++ b/src/App/Page.php @@ -14,7 +14,6 @@ use Friendica\App; use Friendica\AppHelper; use Friendica\Content\Nav; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues; use Friendica\Core\Renderer; @@ -22,12 +21,14 @@ use Friendica\Core\Session\Model\UserSession; use Friendica\Core\System; use Friendica\Core\Theme; use Friendica\DI; +use Friendica\Event\HtmlFilterEvent; use Friendica\Network\HTTPException; use Friendica\Util\Images; use Friendica\Util\Network; use Friendica\Util\Profiler; use Friendica\Util\Strings; use GuzzleHttp\Psr7\Utils; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ResponseInterface; /** @@ -70,6 +71,8 @@ class Page implements ArrayAccess */ private $basePath; + private EventDispatcherInterface $eventDispatcher; + private $timestamp = 0; private $method = ''; private $module = ''; @@ -78,10 +81,11 @@ class Page implements ArrayAccess /** * @param string $basepath The Page basepath */ - public function __construct(string $basepath) + public function __construct(string $basepath, EventDispatcherInterface $eventDispatcher) { - $this->timestamp = microtime(true); - $this->basePath = $basepath; + $this->timestamp = microtime(true); + $this->basePath = $basepath; + $this->eventDispatcher = $eventDispatcher; } public function setLogging(string $method, string $module, string $command) @@ -229,7 +233,10 @@ class Page implements ArrayAccess $touch_icon = 'images/friendica-192.png'; } - Hook::callAll('head', $this->page['htmlhead']); + $this->page['htmlhead'] = $this->eventDispatcher->dispatch(new HtmlFilterEvent( + HtmlFilterEvent::HEAD, + $this->page['htmlhead'] + ))->getHtml(); $tpl = Renderer::getMarkupTemplate('head.tpl'); /* put the head template at the beginning of page['htmlhead'] @@ -351,7 +358,10 @@ class Page implements ArrayAccess ]); } - Hook::callAll('footer', $this->page['footer']); + $this->page['footer'] = $this->eventDispatcher->dispatch(new HtmlFilterEvent( + HtmlFilterEvent::FOOTER, + $this->page['footer'] + ))->getHtml(); $tpl = Renderer::getMarkupTemplate('footer.tpl'); $this->page['footer'] = Renderer::replaceMacros($tpl, [ @@ -376,7 +386,10 @@ class Page implements ArrayAccess { // initialise content region if ($mode->isNormal()) { - Hook::callAll('page_content_top', $this->page['content']); + $this->page['content'] = $this->eventDispatcher->dispatch(new HtmlFilterEvent( + HtmlFilterEvent::PAGE_CONTENT_TOP, + $this->page['content'] + ))->getHtml(); } $this->page['content'] .= (string)$response->getBody(); @@ -474,7 +487,10 @@ class Page implements ArrayAccess $profiler->set(microtime(true) - $timestamp, 'aftermath'); if (!$mode->isAjax()) { - Hook::callAll('page_end', $this->page['content']); + $this->page['content'] = $this->eventDispatcher->dispatch(new HtmlFilterEvent( + HtmlFilterEvent::PAGE_END, + $this->page['content'] + ))->getHtml(); } // Add the navigation (menu) template diff --git a/src/Event/Event.php b/src/Event/Event.php new file mode 100644 index 0000000000..248b310b78 --- /dev/null +++ b/src/Event/Event.php @@ -0,0 +1,33 @@ +name = $name; + } + + public function getName(): string + { + return $this->name; + } +} diff --git a/src/Event/EventDispatcher.php b/src/Event/EventDispatcher.php new file mode 100644 index 0000000000..6175996bc6 --- /dev/null +++ b/src/Event/EventDispatcher.php @@ -0,0 +1,35 @@ +getName(); + } + + return parent::dispatch($event, $eventName); + } +} diff --git a/src/Event/HtmlFilterEvent.php b/src/Event/HtmlFilterEvent.php new file mode 100644 index 0000000000..d8b7b742b8 --- /dev/null +++ b/src/Event/HtmlFilterEvent.php @@ -0,0 +1,49 @@ +name = $name; + $this->html = $html; + } + + public function getName(): string + { + return $this->name; + } + + public function getHtml(): string + { + return $this->html; + } + + public function setHtml(string $html): void + { + $this->html = $html; + } +} diff --git a/src/Event/NamedEvent.php b/src/Event/NamedEvent.php new file mode 100644 index 0000000000..424649664c --- /dev/null +++ b/src/Event/NamedEvent.php @@ -0,0 +1,18 @@ + 'init_1', + HtmlFilterEvent::HEAD => 'head', + HtmlFilterEvent::FOOTER => 'footer', + HtmlFilterEvent::PAGE_CONTENT_TOP => 'page_content_top', + HtmlFilterEvent::PAGE_END => 'page_end', + ]; + + /** + * @return array + */ + public static function getStaticSubscribedEvents(): array + { + return [ + Event::INIT => 'onNamedEvent', + HtmlFilterEvent::HEAD => 'onHtmlFilterEvent', + HtmlFilterEvent::FOOTER => 'onHtmlFilterEvent', + HtmlFilterEvent::PAGE_CONTENT_TOP => 'onHtmlFilterEvent', + HtmlFilterEvent::PAGE_END => 'onHtmlFilterEvent', + ]; + } + + public static function onNamedEvent(NamedEvent $event): void + { + $name = $event->getName(); + + $name = static::$eventMapper[$name] ?? $name; + + static::callHook($name, ''); + } + + public static function onHtmlFilterEvent(HtmlFilterEvent $event): void + { + $name = $event->getName(); + + $name = static::$eventMapper[$name] ?? $name; + + $event->setHtml( + static::callHook($name, $event->getHtml()) + ); + } + + /** + * @param string|array $data + * + * @return string|array + */ + private static function callHook(string $name, $data) + { + // Little hack to allow mocking the Hook call in tests. + if (static::$mockedCallHook instanceof \Closure) { + return (static::$mockedCallHook)->__invoke($name, $data); + } + + Hook::callAll($name, $data); + + return $data; + } +} diff --git a/src/EventSubscriber/StaticEventSubscriber.php b/src/EventSubscriber/StaticEventSubscriber.php new file mode 100644 index 0000000000..16b60fb66d --- /dev/null +++ b/src/EventSubscriber/StaticEventSubscriber.php @@ -0,0 +1,32 @@ + 'onEvent']; + * ``` + * + * @return array + */ + public static function getStaticSubscribedEvents(): array; +} diff --git a/static/dependencies.config.php b/static/dependencies.config.php index f1c2f4e52e..5ffaf134e4 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -182,6 +182,9 @@ return (function(string $basepath, array $getVars, array $serverVars, array $coo ['create', [], Dice::CHAIN_CALL], ], ], + \Psr\EventDispatcher\EventDispatcherInterface::class => [ + 'instanceOf' => \Friendica\Event\EventDispatcher::class, + ], \Friendica\Core\Logger\Capability\IHaveCallIntrospections::class => [ 'instanceOf' => \Friendica\Core\Logger\Util\Introspection::class, 'constructParams' => [ diff --git a/tests/Unit/Event/EventDispatcherTest.php b/tests/Unit/Event/EventDispatcherTest.php new file mode 100644 index 0000000000..2cc1527164 --- /dev/null +++ b/tests/Unit/Event/EventDispatcherTest.php @@ -0,0 +1,37 @@ +assertInstanceOf(EventDispatcherInterface::class, $eventDispatcher); + } + + public function testDispatchANamedEventUsesNameAsEventName(): void + { + $eventDispatcher = new EventDispatcher(); + + $eventDispatcher->addListener('test', function (NamedEvent $event) { + $this->assertSame('test', $event->getName()); + }); + + $eventDispatcher->dispatch(new Event('test')); + } +} diff --git a/tests/Unit/Event/EventTest.php b/tests/Unit/Event/EventTest.php new file mode 100644 index 0000000000..8d7f882451 --- /dev/null +++ b/tests/Unit/Event/EventTest.php @@ -0,0 +1,46 @@ +assertInstanceOf(NamedEvent::class, $event); + } + + public static function getPublicConstants(): array + { + return [ + [Event::INIT, 'friendica.init'], + ]; + } + + /** + * @dataProvider getPublicConstants + */ + public function testPublicConstantsAreAvailable($value, $expected): void + { + $this->assertSame($expected, $value); + } + + public function testGetNameReturnsName(): void + { + $event = new Event('test'); + + $this->assertSame('test', $event->getName()); + } +} diff --git a/tests/Unit/Event/HtmlFilterEventTest.php b/tests/Unit/Event/HtmlFilterEventTest.php new file mode 100644 index 0000000000..ae1d27a5ad --- /dev/null +++ b/tests/Unit/Event/HtmlFilterEventTest.php @@ -0,0 +1,69 @@ +assertInstanceOf(NamedEvent::class, $event); + } + + public static function getPublicConstants(): array + { + return [ + [HtmlFilterEvent::HEAD, 'friendica.html.head'], + [HtmlFilterEvent::FOOTER, 'friendica.html.footer'], + [HtmlFilterEvent::PAGE_CONTENT_TOP, 'friendica.html.page_content_top'], + [HtmlFilterEvent::PAGE_END, 'friendica.html.page_end'], + ]; + } + + /** + * @dataProvider getPublicConstants + */ + public function testPublicConstantsAreAvailable($value, $expected): void + { + $this->assertSame($expected, $value); + } + + public function testGetNameReturnsName(): void + { + $event = new HtmlFilterEvent('test', ''); + + $this->assertSame('test', $event->getName()); + } + + public function testGetHtmlReturnsCorrectString(): void + { + $data = 'original'; + + $event = new HtmlFilterEvent('test', $data); + + $this->assertSame($data, $event->getHtml()); + } + + public function testSetHtmlUpdatesHtml(): void + { + $event = new HtmlFilterEvent('test', 'original'); + + $expected = 'updated'; + + $event->setHtml($expected); + + $this->assertSame($expected, $event->getHtml()); + } +} diff --git a/tests/Unit/EventSubscriber/HookEventBridgeTest.php b/tests/Unit/EventSubscriber/HookEventBridgeTest.php new file mode 100644 index 0000000000..a9cc237bb7 --- /dev/null +++ b/tests/Unit/EventSubscriber/HookEventBridgeTest.php @@ -0,0 +1,114 @@ +assertTrue( + is_subclass_of(HookEventBridge::class, StaticEventSubscriber::class, true), + HookEventBridge::class . ' does not implement ' . StaticEventSubscriber::class + ); + } + + public function testGetStaticSubscribedEventsReturnsStaticMethods(): void + { + $expected = [ + Event::INIT => 'onNamedEvent', + HtmlFilterEvent::HEAD => 'onHtmlFilterEvent', + HtmlFilterEvent::FOOTER => 'onHtmlFilterEvent', + HtmlFilterEvent::PAGE_CONTENT_TOP => 'onHtmlFilterEvent', + HtmlFilterEvent::PAGE_END => 'onHtmlFilterEvent', + ]; + + $this->assertSame( + $expected, + HookEventBridge::getStaticSubscribedEvents() + ); + + foreach ($expected as $methodName) { + $this->assertTrue( + method_exists(HookEventBridge::class, $methodName), + $methodName . '() is not defined' + ); + + $this->assertTrue( + (new \ReflectionMethod(HookEventBridge::class, $methodName))->isStatic(), + $methodName . '() is not static' + ); + } + } + + public static function getNamedEventData(): array + { + return [ + ['test', 'test'], + [Event::INIT, 'init_1'], + ]; + } + + /** + * @dataProvider getNamedEventData + */ + public function testOnNamedEventCallsHook($name, $expected): void + { + $event = new Event($name); + + $reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook'); + $reflectionProperty->setAccessible(true); + + $reflectionProperty->setValue(null, function (string $name, $data) use ($expected) { + $this->assertSame($expected, $name); + $this->assertSame('', $data); + + return $data; + }); + + HookEventBridge::onNamedEvent($event); + } + + public static function getHtmlFilterEventData(): array + { + return [ + ['test', 'test'], + [HtmlFilterEvent::HEAD, 'head'], + [HtmlFilterEvent::FOOTER, 'footer'], + [HtmlFilterEvent::PAGE_CONTENT_TOP, 'page_content_top'], + [HtmlFilterEvent::PAGE_END, 'page_end'], + ]; + } + + /** + * @dataProvider getHtmlFilterEventData + */ + public function testOnHtmlFilterEventCallsHookWithCorrectValue($name, $expected): void + { + $event = new HtmlFilterEvent($name, 'original'); + + $reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook'); + $reflectionProperty->setAccessible(true); + + $reflectionProperty->setValue(null, function (string $name, $data) use ($expected) { + $this->assertSame($expected, $name); + $this->assertSame('original', $data); + + return $data; + }); + + HookEventBridge::onHtmlFilterEvent($event); + } +} diff --git a/tests/Unit/Util/BasePathTest.php b/tests/Unit/Util/BasePathTest.php index 26c495b7fe..dbdf9bd261 100644 --- a/tests/Unit/Util/BasePathTest.php +++ b/tests/Unit/Util/BasePathTest.php @@ -5,7 +5,7 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later -declare(strict_types = 1); +declare(strict_types=1); namespace Friendica\Test\Unit\Util; @@ -16,48 +16,48 @@ class BasePathTest extends TestCase { public static function getDataPaths(): array { - $basePath = dirname(__DIR__, 3); + $basePath = dirname(__DIR__, 3); $configPath = $basePath . DIRECTORY_SEPARATOR . 'config'; return [ 'fullPath' => [ - 'server' => [], - 'baseDir' => $configPath, + 'server' => [], + 'baseDir' => $configPath, 'expected' => $configPath, ], 'relative' => [ - 'server' => [], - 'baseDir' => 'config', + 'server' => [], + 'baseDir' => 'config', 'expected' => $configPath, ], 'document_root' => [ 'server' => [ 'DOCUMENT_ROOT' => $configPath, ], - 'baseDir' => '/noooop', + 'baseDir' => '/noooop', 'expected' => $configPath, ], 'pwd' => [ 'server' => [ 'PWD' => $configPath, ], - 'baseDir' => '/noooop', + 'baseDir' => '/noooop', 'expected' => $configPath, ], 'no_overwrite' => [ 'server' => [ 'DOCUMENT_ROOT' => $basePath, - 'PWD' => $basePath, + 'PWD' => $basePath, ], - 'baseDir' => 'config', + 'baseDir' => 'config', 'expected' => $configPath, ], 'no_overwrite_if_invalid' => [ 'server' => [ 'DOCUMENT_ROOT' => '/nopopop', - 'PWD' => $configPath, + 'PWD' => $configPath, ], - 'baseDir' => '/noatgawe22fafa', + 'baseDir' => '/noatgawe22fafa', 'expected' => $configPath, ] ]; diff --git a/tests/Unit/Util/CryptoTest.php b/tests/Unit/Util/CryptoTest.php index 9dbffb29b4..41fb1e2826 100644 --- a/tests/Unit/Util/CryptoTest.php +++ b/tests/Unit/Util/CryptoTest.php @@ -5,7 +5,7 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later -declare(strict_types = 1); +declare(strict_types=1); namespace Friendica\Test\Unit\Util;