diff --git a/libraries/src/Application/AdministratorApplication.php b/libraries/src/Application/AdministratorApplication.php index 45a9d5ecc6ffa..a40fc7fc35955 100644 --- a/libraries/src/Application/AdministratorApplication.php +++ b/libraries/src/Application/AdministratorApplication.php @@ -11,7 +11,9 @@ use Joomla\Application\Web\WebClient; use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Event\Application\AfterDispatchEvent; use Joomla\CMS\Event\Application\AfterInitialiseDocumentEvent; +use Joomla\CMS\Event\Application\AfterRouteEvent; use Joomla\CMS\Factory; use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Input\Input; @@ -149,7 +151,10 @@ public function dispatch($component = null) $document->setBuffer($contents, ['type' => 'component']); // Trigger the onAfterDispatch event. - $this->triggerEvent('onAfterDispatch'); + $this->dispatchEvent( + 'onAfterDispatch', + new AfterDispatchEvent('onAfterDispatch', ['subject' => $this]) + ); } /** @@ -454,8 +459,11 @@ protected function route() $this->isHandlingMultiFactorAuthentication(); // Trigger the onAfterRoute event. - PluginHelper::importPlugin('system'); - $this->triggerEvent('onAfterRoute'); + PluginHelper::importPlugin('system', null, true, $this->getDispatcher()); + $this->dispatchEvent( + 'onAfterRoute', + new AfterRouteEvent('onAfterRoute', ['subject' => $this]) + ); } /** diff --git a/libraries/src/Application/ApiApplication.php b/libraries/src/Application/ApiApplication.php index 83f2dab317fa3..b0fd0b419a0c2 100644 --- a/libraries/src/Application/ApiApplication.php +++ b/libraries/src/Application/ApiApplication.php @@ -12,7 +12,10 @@ use Joomla\Application\Web\WebClient; use Joomla\CMS\Access\Exception\AuthenticationFailed; use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Event\Application\AfterApiRouteEvent; use Joomla\CMS\Event\Application\AfterInitialiseDocumentEvent; +use Joomla\CMS\Event\Application\AfterDispatchEvent; +use Joomla\CMS\Event\Application\BeforeApiRouteEvent; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Router\ApiRouter; @@ -228,8 +231,12 @@ protected function route() $router = $this->getContainer()->get(ApiRouter::class); // Trigger the onBeforeApiRoute event. - PluginHelper::importPlugin('webservices'); - $this->triggerEvent('onBeforeApiRoute', [&$router, $this]); + PluginHelper::importPlugin('webservices', null, true, $this->getDispatcher()); + $this->dispatchEvent( + 'onBeforeApiRoute', + new BeforeApiRouteEvent('onBeforeApiRoute', ['router' => $router, 'subject' => $this]) + ); + $caught404 = false; $method = $this->input->getMethod(); @@ -300,7 +307,10 @@ protected function route() } } - $this->triggerEvent('onAfterApiRoute', [$this]); + $this->dispatchEvent( + 'onAfterApiRoute', + new AfterApiRouteEvent('onAfterApiRoute', ['subject' => $this]) + ); if (!isset($route['vars']['public']) || $route['vars']['public'] === false) { if (!$this->login(['username' => ''], ['silent' => true, 'action' => 'core.login.api'])) { @@ -414,6 +424,7 @@ public function dispatch($component = null) $document = Factory::getDocument(); // Trigger the onAfterInitialiseDocument event. + PluginHelper::importPlugin('system', null, true, $this->getDispatcher()); $this->dispatchEvent( 'onAfterInitialiseDocument', new AfterInitialiseDocumentEvent('onAfterInitialiseDocument', ['subject' => $this, 'document' => $document]) @@ -423,6 +434,9 @@ public function dispatch($component = null) $document->setBuffer($contents, ['type' => 'component']); // Trigger the onAfterDispatch event. - $this->triggerEvent('onAfterDispatch'); + $this->dispatchEvent( + 'onAfterDispatch', + new AfterDispatchEvent('onAfterDispatch', ['subject' => $this]) + ); } } diff --git a/libraries/src/Application/CMSApplication.php b/libraries/src/Application/CMSApplication.php index 1ba20bbf70c72..aae85ccb8eb86 100644 --- a/libraries/src/Application/CMSApplication.php +++ b/libraries/src/Application/CMSApplication.php @@ -12,7 +12,13 @@ use Joomla\Application\SessionAwareWebApplicationTrait; use Joomla\Application\Web\WebClient; use Joomla\CMS\Authentication\Authentication; -use Joomla\CMS\Event\AbstractEvent; +use Joomla\CMS\Event\Application\AfterCompressEvent; +use Joomla\CMS\Event\Application\AfterInitialiseEvent; +use Joomla\CMS\Event\Application\AfterRenderEvent; +use Joomla\CMS\Event\Application\AfterRespondEvent; +use Joomla\CMS\Event\Application\AfterRouteEvent; +use Joomla\CMS\Event\Application\BeforeRenderEvent; +use Joomla\CMS\Event\Application\BeforeRespondEvent; use Joomla\CMS\Event\ErrorEvent; use Joomla\CMS\Exception\ExceptionHandler; use Joomla\CMS\Extension\ExtensionManagerTrait; @@ -303,33 +309,40 @@ public function execute() $this->compress(); // Trigger the onAfterCompress event. - $this->triggerEvent('onAfterCompress'); + $this->dispatchEvent( + 'onAfterCompress', + new AfterCompressEvent('onAfterCompress', ['subject' => $this]) + ); } } catch (\Throwable $throwable) { - /** @var ErrorEvent $event */ - $event = AbstractEvent::create( + $event = new ErrorEvent( 'onError', [ 'subject' => $throwable, - 'eventClass' => ErrorEvent::class, 'application' => $this, ] ); // Trigger the onError event. - $this->triggerEvent('onError', $event); + $this->dispatchEvent('onError', $event); ExceptionHandler::handleException($event->getError()); } // Trigger the onBeforeRespond event. - $this->getDispatcher()->dispatch('onBeforeRespond'); + $this->dispatchEvent( + 'onBeforeRespond', + new BeforeRespondEvent('onBeforeRespond', ['subject' => $this]) + ); // Send the application response. $this->respond(); // Trigger the onAfterRespond event. - $this->getDispatcher()->dispatch('onAfterRespond'); + $this->dispatchEvent( + 'onAfterRespond', + new AfterRespondEvent('onAfterRespond', ['subject' => $this]) + ); } /** @@ -738,11 +751,14 @@ protected function initialiseApp($options = []) $this->set('editor', $editor); // Load the behaviour plugins - PluginHelper::importPlugin('behaviour'); + PluginHelper::importPlugin('behaviour', null, true, $this->getDispatcher()); // Trigger the onAfterInitialise event. - PluginHelper::importPlugin('system'); - $this->triggerEvent('onAfterInitialise'); + PluginHelper::importPlugin('system', null, true, $this->getDispatcher()); + $this->dispatchEvent( + 'onAfterInitialise', + new AfterInitialiseEvent('onAfterInitialise', ['subject' => $this]) + ); } /** @@ -822,7 +838,7 @@ public function login($credentials, $options = []) $response = $authenticate->authenticate($credentials, $options); // Import the user plugin group. - PluginHelper::importPlugin('user'); + PluginHelper::importPlugin('user', null, true, $this->getDispatcher()); if ($response->status === Authentication::STATUS_SUCCESS) { /* @@ -939,7 +955,7 @@ public function logout($userid = null, $options = []) } // Import the user plugin group. - PluginHelper::importPlugin('user'); + PluginHelper::importPlugin('user', null, true, $this->getDispatcher()); // OK, the credentials are built. Lets fire the onLogout event. $results = $this->triggerEvent('onUserLogout', [$parameters, $options]); @@ -1012,8 +1028,11 @@ protected function render() $this->document->parse($this->docOptions); // Trigger the onBeforeRender event. - PluginHelper::importPlugin('system'); - $this->triggerEvent('onBeforeRender'); + PluginHelper::importPlugin('system', null, true, $this->getDispatcher()); + $this->dispatchEvent( + 'onBeforeRender', + new BeforeRenderEvent('onBeforeRender', ['subject' => $this]) + ); $caching = false; @@ -1028,7 +1047,10 @@ protected function render() $this->setBody($data); // Trigger the onAfterRender event. - $this->triggerEvent('onAfterRender'); + $this->dispatchEvent( + 'onAfterRender', + new AfterRenderEvent('onAfterRender', ['subject' => $this]) + ); // Mark afterRender in the profiler. JDEBUG ? $this->profiler->mark('afterRender') : null; @@ -1098,8 +1120,11 @@ protected function route() } // Trigger the onAfterRoute event. - PluginHelper::importPlugin('system'); - $this->triggerEvent('onAfterRoute'); + PluginHelper::importPlugin('system', null, true, $this->getDispatcher()); + $this->dispatchEvent( + 'onAfterRoute', + new AfterRouteEvent('onAfterRoute', ['subject' => $this]) + ); } /** diff --git a/libraries/src/Application/CliApplication.php b/libraries/src/Application/CliApplication.php index 43d3ab2823ea2..dfe6d2512b561 100644 --- a/libraries/src/Application/CliApplication.php +++ b/libraries/src/Application/CliApplication.php @@ -13,6 +13,8 @@ use Joomla\CMS\Application\CLI\CliInput; use Joomla\CMS\Application\CLI\CliOutput; use Joomla\CMS\Application\CLI\Output\Stdout; +use Joomla\CMS\Event\Application\AfterExecuteEvent; +use Joomla\CMS\Event\Application\BeforeExecuteEvent; use Joomla\CMS\Extension\ExtensionManagerTrait; use Joomla\CMS\Factory; use Joomla\CMS\Language\Language; @@ -257,13 +259,19 @@ public function execute() $this->createExtensionNamespaceMap(); // Trigger the onBeforeExecute event - $this->triggerEvent('onBeforeExecute'); + $this->dispatchEvent( + 'onBeforeExecute', + new BeforeExecuteEvent('onBeforeExecute', ['subject' => $this, 'container' => $this->getContainer()]) + ); // Perform application routines. $this->doExecute(); // Trigger the onAfterExecute event. - $this->triggerEvent('onAfterExecute'); + $this->dispatchEvent( + 'onAfterExecute', + new AfterExecuteEvent('onAfterExecute', ['subject' => $this]) + ); } /** diff --git a/libraries/src/Application/ConsoleApplication.php b/libraries/src/Application/ConsoleApplication.php index 2aea95699ec39..6f836a04b0ba9 100644 --- a/libraries/src/Application/ConsoleApplication.php +++ b/libraries/src/Application/ConsoleApplication.php @@ -252,8 +252,8 @@ public function execute() $this->populateHttpHost(); // Import CMS plugin groups to be able to subscribe to events - PluginHelper::importPlugin('system'); - PluginHelper::importPlugin('console'); + PluginHelper::importPlugin('system', null, true, $this->getDispatcher()); + PluginHelper::importPlugin('console', null, true, $this->getDispatcher()); parent::execute(); } diff --git a/libraries/src/Application/DaemonApplication.php b/libraries/src/Application/DaemonApplication.php index 007257e9f81b1..a50cf3b45bdbe 100644 --- a/libraries/src/Application/DaemonApplication.php +++ b/libraries/src/Application/DaemonApplication.php @@ -9,6 +9,10 @@ namespace Joomla\CMS\Application; +use Joomla\CMS\Event\Application\AfterExecuteEvent; +use Joomla\CMS\Event\Application\BeforeExecuteEvent; +use Joomla\CMS\Event\Application\DeamonForkEvent; +use Joomla\CMS\Event\Application\DeamonReceiveSignalEvent; use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Input\Cli; use Joomla\CMS\Log\Log; @@ -163,7 +167,13 @@ public static function signal($signal) } // Fire the onReceiveSignal event. - static::$instance->triggerEvent('onReceiveSignal', [$signal]); + static::$instance->getDispatcher()->dispatch( + 'onReceiveSignal', + new DeamonReceiveSignalEvent('onReceiveSignal', [ + 'signal' => $signal, + 'subject' => static::$instance, + ]) + ); switch ($signal) { case SIGINT: @@ -345,7 +355,10 @@ public function loadConfiguration($data) public function execute() { // Trigger the onBeforeExecute event - $this->triggerEvent('onBeforeExecute'); + $this->dispatchEvent( + 'onBeforeExecute', + new BeforeExecuteEvent('onBeforeExecute', ['subject' => $this, 'container' => $this->getContainer()]) + ); // Enable basic garbage collection. gc_enable(); @@ -375,7 +388,10 @@ public function execute() } // Trigger the onAfterExecute event. - $this->triggerEvent('onAfterExecute'); + $this->dispatchEvent( + 'onAfterExecute', + new AfterExecuteEvent('onAfterExecute', ['subject' => $this]) + ); } /** @@ -768,7 +784,10 @@ protected function writeProcessIdFile() protected function postFork() { // Trigger the onFork event. - $this->triggerEvent('onFork'); + $this->dispatchEvent( + 'onFork', + new DeamonForkEvent('onFork', ['subject' => $this]) + ); } /** diff --git a/libraries/src/Application/SiteApplication.php b/libraries/src/Application/SiteApplication.php index fec7e795894eb..03d95d8e81cf9 100644 --- a/libraries/src/Application/SiteApplication.php +++ b/libraries/src/Application/SiteApplication.php @@ -13,7 +13,9 @@ use Joomla\CMS\Cache\CacheControllerFactoryAwareTrait; use Joomla\CMS\Cache\Controller\OutputController; use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Event\Application\AfterDispatchEvent; use Joomla\CMS\Event\Application\AfterInitialiseDocumentEvent; +use Joomla\CMS\Event\Application\AfterRouteEvent; use Joomla\CMS\Factory; use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Input\Input; @@ -217,7 +219,10 @@ public function dispatch($component = null) $document->setBuffer($contents, ['type' => 'component']); // Trigger the onAfterDispatch event. - $this->triggerEvent('onAfterDispatch'); + $this->dispatchEvent( + 'onAfterDispatch', + new AfterDispatchEvent('onAfterDispatch', ['subject' => $this]) + ); } /** @@ -793,8 +798,11 @@ protected function route() } // Trigger the onAfterRoute event. - PluginHelper::importPlugin('system'); - $this->triggerEvent('onAfterRoute'); + PluginHelper::importPlugin('system', null, true, $this->getDispatcher()); + $this->dispatchEvent( + 'onAfterRoute', + new AfterRouteEvent('onAfterRoute', ['subject' => $this]) + ); $Itemid = $this->input->getInt('Itemid', null); $this->authorise($Itemid); diff --git a/libraries/src/Application/WebApplication.php b/libraries/src/Application/WebApplication.php index f69b5261cacf8..2103970c4ff9c 100644 --- a/libraries/src/Application/WebApplication.php +++ b/libraries/src/Application/WebApplication.php @@ -12,6 +12,12 @@ use Joomla\Application\AbstractWebApplication; use Joomla\Application\Web\WebClient; use Joomla\CMS\Document\Document; +use Joomla\CMS\Event\Application\AfterExecuteEvent; +use Joomla\CMS\Event\Application\AfterRenderEvent; +use Joomla\CMS\Event\Application\AfterRespondEvent; +use Joomla\CMS\Event\Application\BeforeExecuteEvent; +use Joomla\CMS\Event\Application\BeforeRenderEvent; +use Joomla\CMS\Event\Application\BeforeRespondEvent; use Joomla\CMS\Factory; use Joomla\CMS\Input\Input; use Joomla\CMS\Language\Language; @@ -154,24 +160,36 @@ public static function getInstance($name = null) public function execute() { // Trigger the onBeforeExecute event. - $this->triggerEvent('onBeforeExecute'); + $this->dispatchEvent( + 'onBeforeExecute', + new BeforeExecuteEvent('onBeforeExecute', ['subject' => $this]) + ); // Perform application routines. $this->doExecute(); // Trigger the onAfterExecute event. - $this->triggerEvent('onAfterExecute'); + $this->dispatchEvent( + 'onAfterExecute', + new AfterExecuteEvent('onAfterExecute', ['subject' => $this]) + ); // If we have an application document object, render it. if ($this->document instanceof Document) { // Trigger the onBeforeRender event. - $this->triggerEvent('onBeforeRender'); + $this->dispatchEvent( + 'onBeforeRender', + new BeforeRenderEvent('onBeforeRender', ['subject' => $this]) + ); // Render the application output. $this->render(); // Trigger the onAfterRender event. - $this->triggerEvent('onAfterRender'); + $this->dispatchEvent( + 'onAfterRender', + new AfterRenderEvent('onAfterRender', ['subject' => $this]) + ); } // If gzip compression is enabled in configuration and the server is compliant, compress the output. @@ -180,13 +198,19 @@ public function execute() } // Trigger the onBeforeRespond event. - $this->triggerEvent('onBeforeRespond'); + $this->dispatchEvent( + 'onBeforeRespond', + new BeforeRespondEvent('onBeforeRespond', ['subject' => $this]) + ); // Send the application response. $this->respond(); // Trigger the onAfterRespond event. - $this->triggerEvent('onAfterRespond'); + $this->dispatchEvent( + 'onAfterRespond', + new AfterRespondEvent('onAfterRespond', ['subject' => $this]) + ); } /** diff --git a/libraries/src/Document/Renderer/Html/MetasRenderer.php b/libraries/src/Document/Renderer/Html/MetasRenderer.php index 6c8b2d2175356..3b4ed61d3537e 100644 --- a/libraries/src/Document/Renderer/Html/MetasRenderer.php +++ b/libraries/src/Document/Renderer/Html/MetasRenderer.php @@ -10,6 +10,7 @@ namespace Joomla\CMS\Document\Renderer\Html; use Joomla\CMS\Document\DocumentRenderer; +use Joomla\CMS\Event\Application\BeforeCompileHeadEvent; use Joomla\CMS\Factory; use Joomla\CMS\Helper\TagsHelper; use Joomla\CMS\Uri\Uri; @@ -58,7 +59,10 @@ public function render($head, $params = [], $content = null) } // Trigger the onBeforeCompileHead event - $app->triggerEvent('onBeforeCompileHead'); + $app->getDispatcher()->dispatch( + 'onBeforeCompileHead', + new BeforeCompileHeadEvent('onBeforeCompileHead', ['subject' => $app, 'document' => $this->_doc]) + ); // Add Script Options as inline asset $scriptOptions = $this->_doc->getScriptOptions(); diff --git a/libraries/src/Event/AbstractEvent.php b/libraries/src/Event/AbstractEvent.php index 40060b4ce8237..8177d1cadd94c 100644 --- a/libraries/src/Event/AbstractEvent.php +++ b/libraries/src/Event/AbstractEvent.php @@ -10,7 +10,6 @@ namespace Joomla\CMS\Event; use Joomla\Event\Event; -use Joomla\Event\Event as BaseEvent; use Joomla\String\Normalise; // phpcs:disable PSR1.Files.SideEffects @@ -37,7 +36,7 @@ * * @since 4.0.0 */ -abstract class AbstractEvent extends BaseEvent +abstract class AbstractEvent extends Event { use CoreEventAware; @@ -57,6 +56,11 @@ abstract class AbstractEvent extends BaseEvent */ public static function create(string $eventName, array $arguments = []) { + // Make sure a non-empty subject argument exists and that it is an object + if (empty($arguments['subject']) || !\is_object($arguments['subject'])) { + throw new \BadMethodCallException("No subject given for the $eventName event"); + } + // Get the class name from the arguments, if specified $eventClassName = ''; @@ -66,11 +70,20 @@ public static function create(string $eventName, array $arguments = []) unset($arguments['eventClass']); } + if (!$eventClassName) { + // Look for known class name. + $eventClassName = self::getEventClassByEventName($eventName); + + if ($eventClassName === Event::class) { + $eventClassName = ''; + } + } + /** - * If the class name isn't set/found determine it from the event name, e.g. TableBeforeLoadEvent from + * If the class name isn't set/found determine it from the event name, e.g. Table\BeforeLoadEvent from * the onTableBeforeLoad event name. */ - if (empty($eventClassName) || !class_exists($eventClassName, true)) { + if (!$eventClassName || !class_exists($eventClassName, true)) { $bareName = strpos($eventName, 'on') === 0 ? substr($eventName, 2) : $eventName; $parts = Normalise::fromCamelCase($bareName, true); $eventClassName = __NAMESPACE__ . '\\' . ucfirst(array_shift($parts)) . '\\'; @@ -78,27 +91,11 @@ public static function create(string $eventName, array $arguments = []) $eventClassName .= 'Event'; } - // Make sure a non-empty subject argument exists and that it is an object - if (!isset($arguments['subject']) || empty($arguments['subject']) || !\is_object($arguments['subject'])) { - throw new \BadMethodCallException("No subject given for the $eventName event"); - } - // Create and return the event object if (class_exists($eventClassName, true)) { return new $eventClassName($eventName, $arguments); } - /** - * The detection code above failed. This is to be expected, it was written back when we only - * had the Table events. It does not address most other core events. So, let's use our - * fancier detection instead. - */ - $eventClassName = self::getEventClassByEventName($eventName); - - if (!empty($eventClassName) && ($eventClassName !== Event::class)) { - return new $eventClassName($eventName, $arguments); - } - return new GenericEvent($eventName, $arguments); } diff --git a/libraries/src/Event/Application/AfterApiRouteEvent.php b/libraries/src/Event/Application/AfterApiRouteEvent.php new file mode 100644 index 0000000000000..81e8d0576d3f9 --- /dev/null +++ b/libraries/src/Event/Application/AfterApiRouteEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for AfterApiRoute event + * + * @since __DEPLOY_VERSION__ + */ +class AfterApiRouteEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/AfterCompressEvent.php b/libraries/src/Event/Application/AfterCompressEvent.php new file mode 100644 index 0000000000000..a17801847efc4 --- /dev/null +++ b/libraries/src/Event/Application/AfterCompressEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for AfterCompress event + * + * @since __DEPLOY_VERSION__ + */ +class AfterCompressEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/AfterDispatchEvent.php b/libraries/src/Event/Application/AfterDispatchEvent.php new file mode 100644 index 0000000000000..2fe9f84b38efe --- /dev/null +++ b/libraries/src/Event/Application/AfterDispatchEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for AfterDispatch event + * + * @since __DEPLOY_VERSION__ + */ +class AfterDispatchEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/AfterExecuteEvent.php b/libraries/src/Event/Application/AfterExecuteEvent.php new file mode 100644 index 0000000000000..0fbdee994e645 --- /dev/null +++ b/libraries/src/Event/Application/AfterExecuteEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for AfterExecute event + * + * @since __DEPLOY_VERSION__ + */ +class AfterExecuteEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/AfterInitialiseEvent.php b/libraries/src/Event/Application/AfterInitialiseEvent.php new file mode 100644 index 0000000000000..0fd8d86a08717 --- /dev/null +++ b/libraries/src/Event/Application/AfterInitialiseEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for AfterInitialise event + * + * @since __DEPLOY_VERSION__ + */ +class AfterInitialiseEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/AfterRenderEvent.php b/libraries/src/Event/Application/AfterRenderEvent.php new file mode 100644 index 0000000000000..15d2aaa9bc1a7 --- /dev/null +++ b/libraries/src/Event/Application/AfterRenderEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for AfterRender event + * + * @since __DEPLOY_VERSION__ + */ +class AfterRenderEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/AfterRespondEvent.php b/libraries/src/Event/Application/AfterRespondEvent.php new file mode 100644 index 0000000000000..ea00ae648b2c3 --- /dev/null +++ b/libraries/src/Event/Application/AfterRespondEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for AfterRespond event + * + * @since __DEPLOY_VERSION__ + */ +class AfterRespondEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/AfterRouteEvent.php b/libraries/src/Event/Application/AfterRouteEvent.php new file mode 100644 index 0000000000000..4e5e3fed535c1 --- /dev/null +++ b/libraries/src/Event/Application/AfterRouteEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for AfterRoute event + * + * @since __DEPLOY_VERSION__ + */ +class AfterRouteEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/ApplicationDocumentEvent.php b/libraries/src/Event/Application/ApplicationDocumentEvent.php new file mode 100644 index 0000000000000..31599c1545025 --- /dev/null +++ b/libraries/src/Event/Application/ApplicationDocumentEvent.php @@ -0,0 +1,69 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +use Joomla\CMS\Document\Document; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for Application's Document events + * + * @since __DEPLOY_VERSION__ + */ +abstract class ApplicationDocumentEvent extends ApplicationEvent +{ + /** + * Constructor. + * + * @param string $name The event name. + * @param array $arguments The event arguments. + * + * @throws \BadMethodCallException + * + * @since __DEPLOY_VERSION__ + */ + public function __construct($name, array $arguments = []) + { + if (!\array_key_exists('document', $arguments)) { + throw new \BadMethodCallException("Argument 'document' of event {$name} is required but has not been provided"); + } + + parent::__construct($name, $arguments); + } + + /** + * Setter for the document argument. + * + * @param Document $value The value to set + * + * @return Document + * + * @since __DEPLOY_VERSION__ + */ + protected function setDocument(Document $value): Document + { + return $value; + } + + /** + * Get the event's document object + * + * @return Document + * + * @since __DEPLOY_VERSION__ + */ + public function getDocument(): Document + { + return $this->arguments['document']; + } +} diff --git a/libraries/src/Event/Application/ApplicationEvent.php b/libraries/src/Event/Application/ApplicationEvent.php new file mode 100644 index 0000000000000..ea000282df276 --- /dev/null +++ b/libraries/src/Event/Application/ApplicationEvent.php @@ -0,0 +1,70 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +use Joomla\Application\AbstractApplication; +use Joomla\CMS\Event\AbstractImmutableEvent; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for Application events + * + * @since __DEPLOY_VERSION__ + */ +abstract class ApplicationEvent extends AbstractImmutableEvent +{ + /** + * Constructor. + * + * @param string $name The event name. + * @param array $arguments The event arguments. + * + * @throws \BadMethodCallException + * + * @since __DEPLOY_VERSION__ + */ + public function __construct($name, array $arguments = []) + { + if (!\array_key_exists('subject', $arguments)) { + throw new \BadMethodCallException("Argument 'subject' of event {$name} is required but has not been provided"); + } + + parent::__construct($name, $arguments); + } + + /** + * Setter for the subject argument. + * + * @param AbstractApplication $value The value to set + * + * @return AbstractApplication + * + * @since __DEPLOY_VERSION__ + */ + final protected function setSubject(AbstractApplication $value): AbstractApplication + { + return $value; + } + + /** + * Get the event's application object + * + * @return AbstractApplication + * + * @since __DEPLOY_VERSION__ + */ + final public function getApplication(): AbstractApplication + { + return $this->getArgument('subject'); + } +} diff --git a/libraries/src/Event/Application/BeforeApiRouteEvent.php b/libraries/src/Event/Application/BeforeApiRouteEvent.php new file mode 100644 index 0000000000000..c2e6811b1ccb9 --- /dev/null +++ b/libraries/src/Event/Application/BeforeApiRouteEvent.php @@ -0,0 +1,69 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +use Joomla\CMS\Router\ApiRouter; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for BeforeApiRoute event + * + * @since __DEPLOY_VERSION__ + */ +class BeforeApiRouteEvent extends ApplicationEvent +{ + /** + * Constructor. + * + * @param string $name The event name. + * @param array $arguments The event arguments. + * + * @throws \BadMethodCallException + * + * @since __DEPLOY_VERSION__ + */ + public function __construct($name, array $arguments = []) + { + if (!\array_key_exists('router', $arguments)) { + throw new \BadMethodCallException("Argument 'router' of event {$name} is required but has not been provided"); + } + + parent::__construct($name, $arguments); + } + + /** + * Setter for the router argument. + * + * @param ApiRouter $value The value to set + * + * @return ApiRouter + * + * @since __DEPLOY_VERSION__ + */ + protected function setRouter(ApiRouter $value): ApiRouter + { + return $value; + } + + /** + * Get the event's document object + * + * @return ApiRouter + * + * @since __DEPLOY_VERSION__ + */ + public function getRouter(): ApiRouter + { + return $this->arguments['router']; + } +} diff --git a/libraries/src/Event/Application/BeforeCompileHeadEvent.php b/libraries/src/Event/Application/BeforeCompileHeadEvent.php new file mode 100644 index 0000000000000..857c892a5708c --- /dev/null +++ b/libraries/src/Event/Application/BeforeCompileHeadEvent.php @@ -0,0 +1,24 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects + +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for BeforeCompileHead event + * + * @since __DEPLOY_VERSION__ + */ +class BeforeCompileHeadEvent extends ApplicationDocumentEvent +{ +} diff --git a/libraries/src/Event/Application/BeforeExecuteEvent.php b/libraries/src/Event/Application/BeforeExecuteEvent.php new file mode 100644 index 0000000000000..78df637194b60 --- /dev/null +++ b/libraries/src/Event/Application/BeforeExecuteEvent.php @@ -0,0 +1,36 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +use Joomla\DI\Container; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for BeforeExecute event + * + * @since __DEPLOY_VERSION__ + */ +class BeforeExecuteEvent extends ApplicationEvent +{ + /** + * Get the event's container object + * + * @return ?Container + * + * @since __DEPLOY_VERSION__ + */ + public function getContainer(): ?Container + { + return $this->arguments['container'] ?? null; + } +} diff --git a/libraries/src/Event/Application/BeforeRenderEvent.php b/libraries/src/Event/Application/BeforeRenderEvent.php new file mode 100644 index 0000000000000..523af7518aca9 --- /dev/null +++ b/libraries/src/Event/Application/BeforeRenderEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for BeforeRender event + * + * @since __DEPLOY_VERSION__ + */ +class BeforeRenderEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/BeforeRespondEvent.php b/libraries/src/Event/Application/BeforeRespondEvent.php new file mode 100644 index 0000000000000..35465b2a398a8 --- /dev/null +++ b/libraries/src/Event/Application/BeforeRespondEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for BeforeRespond event + * + * @since __DEPLOY_VERSION__ + */ +class BeforeRespondEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/DeamonForkEvent.php b/libraries/src/Event/Application/DeamonForkEvent.php new file mode 100644 index 0000000000000..e583511f0fce6 --- /dev/null +++ b/libraries/src/Event/Application/DeamonForkEvent.php @@ -0,0 +1,23 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for Fork event for DemonApplication + * + * @since __DEPLOY_VERSION__ + */ +class DeamonForkEvent extends ApplicationEvent +{ +} diff --git a/libraries/src/Event/Application/DeamonReceiveSignalEvent.php b/libraries/src/Event/Application/DeamonReceiveSignalEvent.php new file mode 100644 index 0000000000000..9e068f561c05d --- /dev/null +++ b/libraries/src/Event/Application/DeamonReceiveSignalEvent.php @@ -0,0 +1,67 @@ + + * @license GNU General Public License version 2 or later; see LICENSE + */ + +namespace Joomla\CMS\Event\Application; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Class for ReceiveSignal event for DemonApplication + * + * @since __DEPLOY_VERSION__ + */ +class DeamonReceiveSignalEvent extends ApplicationEvent +{ + /** + * Constructor. + * + * @param string $name The event name. + * @param array $arguments The event arguments. + * + * @throws \BadMethodCallException + * + * @since __DEPLOY_VERSION__ + */ + public function __construct($name, array $arguments = []) + { + if (!\array_key_exists('signal', $arguments)) { + throw new \BadMethodCallException("Argument 'signal' of event {$name} is required but has not been provided"); + } + + parent::__construct($name, $arguments); + } + + /** + * Setter for the signal argument. + * + * @param integer $value The value to set + * + * @return integer + * + * @since __DEPLOY_VERSION__ + */ + protected function setSignal(int $value): int + { + return $value; + } + + /** + * Get the event's signal object + * + * @return integer + * + * @since __DEPLOY_VERSION__ + */ + public function getSignal(): int + { + return $this->arguments['signal']; + } +} diff --git a/libraries/src/Event/CoreEventAware.php b/libraries/src/Event/CoreEventAware.php index 357e9516dd10e..ebf237803991d 100644 --- a/libraries/src/Event/CoreEventAware.php +++ b/libraries/src/Event/CoreEventAware.php @@ -9,7 +9,6 @@ namespace Joomla\CMS\Event; -use Joomla\CMS\Event\Model\BeforeBatchEvent; use Joomla\CMS\Event\Plugin\System\Webauthn\Ajax as PlgSystemWebauthnAjax; use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxChallenge as PlgSystemWebauthnAjaxChallenge; use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxCreate as PlgSystemWebauthnAjaxCreate; @@ -17,35 +16,6 @@ use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxInitCreate as PlgSystemWebauthnAjaxInitCreate; use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxLogin as PlgSystemWebauthnAjaxLogin; use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxSaveLabel as PlgSystemWebauthnAjaxSaveLabel; -use Joomla\CMS\Event\QuickIcon\GetIconEvent; -use Joomla\CMS\Event\Table\AfterBindEvent; -use Joomla\CMS\Event\Table\AfterCheckinEvent; -use Joomla\CMS\Event\Table\AfterCheckoutEvent; -use Joomla\CMS\Event\Table\AfterDeleteEvent; -use Joomla\CMS\Event\Table\AfterHitEvent; -use Joomla\CMS\Event\Table\AfterLoadEvent; -use Joomla\CMS\Event\Table\AfterMoveEvent; -use Joomla\CMS\Event\Table\AfterPublishEvent; -use Joomla\CMS\Event\Table\AfterReorderEvent; -use Joomla\CMS\Event\Table\AfterResetEvent; -use Joomla\CMS\Event\Table\AfterStoreEvent; -use Joomla\CMS\Event\Table\BeforeBindEvent; -use Joomla\CMS\Event\Table\BeforeCheckinEvent; -use Joomla\CMS\Event\Table\BeforeCheckoutEvent; -use Joomla\CMS\Event\Table\BeforeDeleteEvent; -use Joomla\CMS\Event\Table\BeforeHitEvent; -use Joomla\CMS\Event\Table\BeforeLoadEvent; -use Joomla\CMS\Event\Table\BeforeMoveEvent; -use Joomla\CMS\Event\Table\BeforePublishEvent; -use Joomla\CMS\Event\Table\BeforeReorderEvent; -use Joomla\CMS\Event\Table\BeforeResetEvent; -use Joomla\CMS\Event\Table\BeforeStoreEvent; -use Joomla\CMS\Event\Table\CheckEvent; -use Joomla\CMS\Event\Table\ObjectCreateEvent; -use Joomla\CMS\Event\Table\SetNewTagsEvent; -use Joomla\CMS\Event\View\DisplayEvent; -use Joomla\CMS\Event\Workflow\WorkflowFunctionalityUsedEvent; -use Joomla\CMS\Event\Workflow\WorkflowTransitionEvent; use Joomla\Event\Event; // phpcs:disable PSR1.Files.SideEffects @@ -69,43 +39,58 @@ trait CoreEventAware * @since 4.2.0 */ private static $eventNameToConcreteClass = [ + // Application + 'onBeforeExecute' => Application\BeforeExecuteEvent::class, + 'onAfterExecute' => Application\AfterExecuteEvent::class, + 'onAfterInitialise' => Application\AfterInitialiseEvent::class, + 'onAfterRoute' => Application\AfterRouteEvent::class, + 'onBeforeApiRoute' => Application\BeforeApiRouteEvent::class, + 'onAfterApiRoute' => Application\AfterApiRouteEvent::class, + 'onAfterDispatch' => Application\AfterDispatchEvent::class, + 'onBeforeRender' => Application\BeforeRenderEvent::class, + 'onAfterRender' => Application\AfterRenderEvent::class, + 'onBeforeCompileHead' => Application\BeforeCompileHeadEvent::class, + 'onAfterCompress' => Application\AfterCompressEvent::class, + 'onBeforeRespond' => Application\BeforeRespondEvent::class, + 'onAfterRespond' => Application\AfterRespondEvent::class, + 'onError' => ErrorEvent::class, // Model - 'onBeforeBatch' => BeforeBatchEvent::class, + 'onBeforeBatch' => Model\BeforeBatchEvent::class, // Quickicon - 'onGetIcon' => GetIconEvent::class, + 'onGetIcon' => QuickIcon\GetIconEvent::class, // Table - 'onTableAfterBind' => AfterBindEvent::class, - 'onTableAfterCheckin' => AfterCheckinEvent::class, - 'onTableAfterCheckout' => AfterCheckoutEvent::class, - 'onTableAfterDelete' => AfterDeleteEvent::class, - 'onTableAfterHit' => AfterHitEvent::class, - 'onTableAfterLoad' => AfterLoadEvent::class, - 'onTableAfterMove' => AfterMoveEvent::class, - 'onTableAfterPublish' => AfterPublishEvent::class, - 'onTableAfterReorder' => AfterReorderEvent::class, - 'onTableAfterReset' => AfterResetEvent::class, - 'onTableAfterStore' => AfterStoreEvent::class, - 'onTableBeforeBind' => BeforeBindEvent::class, - 'onTableBeforeCheckin' => BeforeCheckinEvent::class, - 'onTableBeforeCheckout' => BeforeCheckoutEvent::class, - 'onTableBeforeDelete' => BeforeDeleteEvent::class, - 'onTableBeforeHit' => BeforeHitEvent::class, - 'onTableBeforeLoad' => BeforeLoadEvent::class, - 'onTableBeforeMove' => BeforeMoveEvent::class, - 'onTableBeforePublish' => BeforePublishEvent::class, - 'onTableBeforeReorder' => BeforeReorderEvent::class, - 'onTableBeforeReset' => BeforeResetEvent::class, - 'onTableBeforeStore' => BeforeStoreEvent::class, - 'onTableCheck' => CheckEvent::class, - 'onTableObjectCreate' => ObjectCreateEvent::class, - 'onTableSetNewTags' => SetNewTagsEvent::class, + 'onTableAfterBind' => Table\AfterBindEvent::class, + 'onTableAfterCheckin' => Table\AfterCheckinEvent::class, + 'onTableAfterCheckout' => Table\AfterCheckoutEvent::class, + 'onTableAfterDelete' => Table\AfterDeleteEvent::class, + 'onTableAfterHit' => Table\AfterHitEvent::class, + 'onTableAfterLoad' => Table\AfterLoadEvent::class, + 'onTableAfterMove' => Table\AfterMoveEvent::class, + 'onTableAfterPublish' => Table\AfterPublishEvent::class, + 'onTableAfterReorder' => Table\AfterReorderEvent::class, + 'onTableAfterReset' => Table\AfterResetEvent::class, + 'onTableAfterStore' => Table\AfterStoreEvent::class, + 'onTableBeforeBind' => Table\BeforeBindEvent::class, + 'onTableBeforeCheckin' => Table\BeforeCheckinEvent::class, + 'onTableBeforeCheckout' => Table\BeforeCheckoutEvent::class, + 'onTableBeforeDelete' => Table\BeforeDeleteEvent::class, + 'onTableBeforeHit' => Table\BeforeHitEvent::class, + 'onTableBeforeLoad' => Table\BeforeLoadEvent::class, + 'onTableBeforeMove' => Table\BeforeMoveEvent::class, + 'onTableBeforePublish' => Table\BeforePublishEvent::class, + 'onTableBeforeReorder' => Table\BeforeReorderEvent::class, + 'onTableBeforeReset' => Table\BeforeResetEvent::class, + 'onTableBeforeStore' => Table\BeforeStoreEvent::class, + 'onTableCheck' => Table\CheckEvent::class, + 'onTableObjectCreate' => Table\ObjectCreateEvent::class, + 'onTableSetNewTags' => Table\SetNewTagsEvent::class, // View - 'onBeforeDisplay' => DisplayEvent::class, - 'onAfterDisplay' => DisplayEvent::class, + 'onBeforeDisplay' => View\DisplayEvent::class, + 'onAfterDisplay' => View\DisplayEvent::class, // Workflow - 'onWorkflowFunctionalityUsed' => WorkflowFunctionalityUsedEvent::class, - 'onWorkflowAfterTransition' => WorkflowTransitionEvent::class, - 'onWorkflowBeforeTransition' => WorkflowTransitionEvent::class, + 'onWorkflowFunctionalityUsed' => Workflow\WorkflowFunctionalityUsedEvent::class, + 'onWorkflowAfterTransition' => Workflow\WorkflowTransitionEvent::class, + 'onWorkflowBeforeTransition' => Workflow\WorkflowTransitionEvent::class, // Plugin: System, WebAuthn 'onAjaxWebauthn' => PlgSystemWebauthnAjax::class, 'onAjaxWebauthnChallenge' => PlgSystemWebauthnAjaxChallenge::class, @@ -114,6 +99,9 @@ trait CoreEventAware 'onAjaxWebauthnInitcreate' => PlgSystemWebauthnAjaxInitCreate::class, 'onAjaxWebauthnLogin' => PlgSystemWebauthnAjaxLogin::class, 'onAjaxWebauthnSavelabel' => PlgSystemWebauthnAjaxSaveLabel::class, + // Extensions + 'onBeforeExtensionBoot' => BeforeExtensionBootEvent::class, + 'onAfterExtensionBoot' => AfterExtensionBootEvent::class, ]; /** diff --git a/plugins/system/cache/src/Extension/Cache.php b/plugins/system/cache/src/Extension/Cache.php index b530e3cfe409d..6e0a2fb34ad53 100644 --- a/plugins/system/cache/src/Extension/Cache.php +++ b/plugins/system/cache/src/Extension/Cache.php @@ -13,6 +13,7 @@ use Joomla\CMS\Cache\CacheController; use Joomla\CMS\Cache\CacheControllerFactoryInterface; use Joomla\CMS\Document\FactoryInterface as DocumentFactoryInterface; +use Joomla\CMS\Event\AbstractEvent; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Profiler\Profiler; @@ -177,7 +178,12 @@ public function onAfterRoute(Event $event) $this->profiler->mark('afterCache'); } - $this->getApplication()->triggerEvent('onAfterRespond'); + $this->getDispatcher()->dispatch('onAfterRespond', AbstractEvent::create( + 'onAfterRespond', + [ + 'subject' => $this->getApplication(), + ] + )); } // Closes the application.