mirror of
https://github.com/friendica/friendica
synced 2025-03-13 14:28:27 +00:00
EventDispatcher proof of concept
This commit is contained in:
parent
827541ed86
commit
9e6f77c4b1
17 changed files with 887 additions and 27 deletions
|
@ -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"
|
||||
|
|
296
composer.lock
generated
296
composer.lock
generated
|
@ -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",
|
||||
|
|
32
src/App.php
32
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);
|
||||
|
|
|
@ -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
|
||||
|
|
33
src/Event/Event.php
Normal file
33
src/Event/Event.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Event;
|
||||
|
||||
/**
|
||||
* One-way Event to inform listener about something happend.
|
||||
*/
|
||||
final class Event implements NamedEvent
|
||||
{
|
||||
/**
|
||||
* Friendica is initialized.
|
||||
*/
|
||||
public const INIT = 'friendica.init';
|
||||
|
||||
private string $name;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
35
src/Event/EventDispatcher.php
Normal file
35
src/Event/EventDispatcher.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Event;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyEventDispatcher;
|
||||
|
||||
/**
|
||||
* Modified Event Dispatcher.
|
||||
*/
|
||||
final class EventDispatcher extends SymfonyEventDispatcher
|
||||
{
|
||||
/**
|
||||
* Add support for named events.
|
||||
*
|
||||
* @template T of object
|
||||
* @param T $event
|
||||
*
|
||||
* @return T The passed $event MUST be returned
|
||||
*/
|
||||
public function dispatch(object $event, ?string $eventName = null): object
|
||||
{
|
||||
if ($eventName === null && $event instanceof NamedEvent) {
|
||||
$eventName = $event->getName();
|
||||
}
|
||||
|
||||
return parent::dispatch($event, $eventName);
|
||||
}
|
||||
}
|
49
src/Event/HtmlFilterEvent.php
Normal file
49
src/Event/HtmlFilterEvent.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Event;
|
||||
|
||||
/**
|
||||
* Allow Event listener to modify HTML.
|
||||
*/
|
||||
final class HtmlFilterEvent implements NamedEvent
|
||||
{
|
||||
public const HEAD = 'friendica.html.head';
|
||||
|
||||
public const FOOTER = 'friendica.html.footer';
|
||||
|
||||
public const PAGE_CONTENT_TOP = 'friendica.html.page_content_top';
|
||||
|
||||
public const PAGE_END = 'friendica.html.page_end';
|
||||
|
||||
private string $name;
|
||||
|
||||
private string $html;
|
||||
|
||||
public function __construct(string $name, string $html)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
18
src/Event/NamedEvent.php
Normal file
18
src/Event/NamedEvent.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Event;
|
||||
|
||||
/**
|
||||
* Interface for named events.
|
||||
*/
|
||||
interface NamedEvent
|
||||
{
|
||||
public function getName(): string;
|
||||
}
|
90
src/EventSubscriber/HookEventBridge.php
Normal file
90
src/EventSubscriber/HookEventBridge.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\EventSubscriber;
|
||||
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Event\Event;
|
||||
use Friendica\Event\HtmlFilterEvent;
|
||||
use Friendica\Event\NamedEvent;
|
||||
|
||||
/**
|
||||
* Bridge between the EventDispatcher and the Hook class.
|
||||
*/
|
||||
final class HookEventBridge implements StaticEventSubscriber
|
||||
{
|
||||
/**
|
||||
* This allows us to mock the Hook call in tests.
|
||||
*
|
||||
* @var \Closure|null
|
||||
*/
|
||||
private static $mockedCallHook = null;
|
||||
|
||||
/**
|
||||
* This maps the new event names to the legacy Hook names.
|
||||
*/
|
||||
private static array $eventMapper = [
|
||||
Event::INIT => 'init_1',
|
||||
HtmlFilterEvent::HEAD => 'head',
|
||||
HtmlFilterEvent::FOOTER => 'footer',
|
||||
HtmlFilterEvent::PAGE_CONTENT_TOP => 'page_content_top',
|
||||
HtmlFilterEvent::PAGE_END => 'page_end',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
32
src/EventSubscriber/StaticEventSubscriber.php
Normal file
32
src/EventSubscriber/StaticEventSubscriber.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\EventSubscriber;
|
||||
|
||||
/**
|
||||
* Define events that should be reacted to.
|
||||
*/
|
||||
interface StaticEventSubscriber
|
||||
{
|
||||
/**
|
||||
* Return an array of events to subscribe to.
|
||||
* The key must the event class name.
|
||||
* The value must the method of the implementing class to call.
|
||||
* The method will be called statically with the event class as first parameter.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```php
|
||||
* return [Event::class => 'onEvent'];
|
||||
* ```
|
||||
*
|
||||
* @return array<class-string, string>
|
||||
*/
|
||||
public static function getStaticSubscribedEvents(): array;
|
||||
}
|
|
@ -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' => [
|
||||
|
|
37
tests/Unit/Event/EventDispatcherTest.php
Normal file
37
tests/Unit/Event/EventDispatcherTest.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Test\Unit\Event;
|
||||
|
||||
use Friendica\Event\Event;
|
||||
use Friendica\Event\EventDispatcher;
|
||||
use Friendica\Event\NamedEvent;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class EventDispatcherTest extends TestCase
|
||||
{
|
||||
public function testImplementationOfInstances(): void
|
||||
{
|
||||
$eventDispatcher = new EventDispatcher();
|
||||
|
||||
$this->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'));
|
||||
}
|
||||
}
|
46
tests/Unit/Event/EventTest.php
Normal file
46
tests/Unit/Event/EventTest.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Test\Unit\Event;
|
||||
|
||||
use Friendica\Event\Event;
|
||||
use Friendica\Event\NamedEvent;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class EventTest extends TestCase
|
||||
{
|
||||
public function testImplementationOfInstances(): void
|
||||
{
|
||||
$event = new Event('test');
|
||||
|
||||
$this->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());
|
||||
}
|
||||
}
|
69
tests/Unit/Event/HtmlFilterEventTest.php
Normal file
69
tests/Unit/Event/HtmlFilterEventTest.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Test\Unit\Event;
|
||||
|
||||
use Friendica\Event\HtmlFilterEvent;
|
||||
use Friendica\Event\NamedEvent;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HtmlFilterEventTest extends TestCase
|
||||
{
|
||||
public function testImplementationOfInstances(): void
|
||||
{
|
||||
$event = new HtmlFilterEvent('test', 'original');
|
||||
|
||||
$this->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());
|
||||
}
|
||||
}
|
114
tests/Unit/EventSubscriber/HookEventBridgeTest.php
Normal file
114
tests/Unit/EventSubscriber/HookEventBridgeTest.php
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Test\Unit\EventSubscriber;
|
||||
|
||||
use Friendica\Event\Event;
|
||||
use Friendica\Event\HtmlFilterEvent;
|
||||
use Friendica\EventSubscriber\HookEventBridge;
|
||||
use Friendica\EventSubscriber\StaticEventSubscriber;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HookEventBridgeTest extends TestCase
|
||||
{
|
||||
public function testCorrectImplementation(): void
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
]
|
||||
];
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue