diff --git a/typo3/sysext/beuser/Classes/Controller/BackendUserController.php b/typo3/sysext/beuser/Classes/Controller/BackendUserController.php index 61a4dab44c4dc50d373944d9db1ade1e60407e90..faeb8a03af512ae5d25d75dca8c84eebdf9c5ae8 100644 --- a/typo3/sysext/beuser/Classes/Controller/BackendUserController.php +++ b/typo3/sysext/beuser/Classes/Controller/BackendUserController.php @@ -14,7 +14,6 @@ namespace TYPO3\CMS\Beuser\Controller; * The TYPO3 project - inspiring people to share! */ -use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Backend\Authentication\Event\SwitchUserEvent; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Session\Backend\SessionBackendInterface; @@ -61,11 +60,6 @@ class BackendUserController extends ActionController */ protected $backendUserSessionRepository; - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; - /** * @param \TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService */ @@ -98,11 +92,6 @@ class BackendUserController extends ActionController $this->backendUserSessionRepository = $backendUserSessionRepository; } - public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher) - { - $this->eventDispatcher = $eventDispatcher; - } - /** * Load and persist module data * diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89870-NewPSR-14EventsForExtbase-relatedSignals.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89870-NewPSR-14EventsForExtbase-relatedSignals.rst new file mode 100644 index 0000000000000000000000000000000000000000..c78dad3c82b4df84f9042b0fb44ee2e0dbefd136 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89870-NewPSR-14EventsForExtbase-relatedSignals.rst @@ -0,0 +1,58 @@ +.. include:: ../../Includes.txt + +=================================================================== +Deprecation: #89870 - New PSR-14 Events for Extbase-related signals +=================================================================== + +See :issue:`89870` + +Description +=========== + +The following signals have been marked as deprecated in favor of new PSR-14 events: + +- :php:`TYPO3\CMS\Extbase\Mvc\Dispatcher::afterRequestDispatch` +- :php:`TYPO3\CMS\Extbase\Mvc\Controller\ActionController::beforeCallActionMethod` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::afterMappingSingleRow` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::beforeGettingObjectData` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterGettingObjectData` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::endInsertObject` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterUpdateObject` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterPersistObject` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterRemoveObject` + +The method :php:`emitBeforeCallActionMethodSignal` in :php:`ActionController` +has been deprecated and is not called by Extbase itself anymore. + +Impact +====== + +Using any of the signals will still work as expected, but will trigger +a deprecation warning. + +Calling the method :php:`emitBeforeCallActionMethodSignal` will trigger a +deprecation warning. + +Affected Installations +====================== + +TYPO3 installations with extensions using the Extbase framework and +Extbase-internal hooks. + + +Migration +========= + +The following new PSR-14-based Events should be used instead: + +- :php:`TYPO3\CMS\Extbase\Event\Mvc\AfterRequestDispatchedEvent` +- :php:`TYPO3\CMS\Extbase\Event\Mvc\BeforeActionCallEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\AfterObjectThawedEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\ModifyQueryBeforeFetchingObjectDataEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\ModifyResultAfterFetchingObjectDataEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityAddedToPersistenceEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent` + +.. index:: PHP-API, PartiallyScanned, ext:extbase diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-89870-NewPSR-14EventsForExtbase-relatedSignals.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-89870-NewPSR-14EventsForExtbase-relatedSignals.rst new file mode 100644 index 0000000000000000000000000000000000000000..ecac644c7a1b30f0bac7f77974ee79897c42daa6 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-89870-NewPSR-14EventsForExtbase-relatedSignals.rst @@ -0,0 +1,44 @@ +.. include:: ../../Includes.txt + +=============================================================== +Feature: #89870 - New PSR-14 Events for Extbase-related signals +=============================================================== + +See :issue:`89870` + +Description +=========== + +The following new PSR-14-based Events are introduced which allow +to modify various concerns in the MVC and persistence stacks of Extbase internals. + +- :php:`TYPO3\CMS\Extbase\Event\Mvc\AfterRequestDispatchedEvent` +- :php:`TYPO3\CMS\Extbase\Event\Mvc\BeforeActionCallEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\AfterObjectThawedEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\ModifyQueryBeforeFetchingObjectDataEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\ModifyResultAfterFetchingObjectDataEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityAddedToPersistenceEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityFinalizedAfterPersistenceEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent` +- :php:`TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent` + + +Impact +====== + +Existing signals are replaced and should not be used anymore, as PSR-14 event classes exactly specify what can be modified or listened to. + +The following signals should not be used anymore then: +- :php:`TYPO3\CMS\Extbase\Mvc\Dispatcher::afterRequestDispatch` +- :php:`TYPO3\CMS\Extbase\Mvc\Controller\ActionController::beforeCallActionMethod` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::afterMappingSingleRow` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::beforeGettingObjectData` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterGettingObjectData` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterInsertObject` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::endInsertObject` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterUpdateObject` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterPersistObject` +- :php:`TYPO3\CMS\Extbase\Persistence\Generic\Backend::afterRemoveObject` + +.. index:: PHP-API, ext:extbase diff --git a/typo3/sysext/extbase/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/extbase/Classes/Compatibility/SlotReplacement.php new file mode 100644 index 0000000000000000000000000000000000000000..7f85165179fb86971286230eb463e4a3b1146e42 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Compatibility/SlotReplacement.php @@ -0,0 +1,162 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Extbase\Compatibility; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\Event\Mvc\AfterRequestDispatchedEvent; +use TYPO3\CMS\Extbase\Event\Mvc\BeforeActionCallEvent; +use TYPO3\CMS\Extbase\Event\Persistence\AfterObjectThawedEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityAddedToPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityFinalizedAfterPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\ModifyQueryBeforeFetchingObjectDataEvent; +use TYPO3\CMS\Extbase\Event\Persistence\ModifyResultAfterFetchingObjectDataEvent; +use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; +use TYPO3\CMS\Extbase\Mvc\Dispatcher; +use TYPO3\CMS\Extbase\Persistence\Generic\Backend; +use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper; +use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher; + +/** + * This class provides a replacement for all existing signals in EXT:extbase of TYPO3 Core, which now act as a + * simple wrapper for PSR-14 events with a simple ("first prioritized") listener implementation. + * + * @internal Please note that this class will likely be removed in TYPO3 v11, and Extension Authors should + * switch to PSR-14 event listeners. + */ +class SlotReplacement +{ + /** + * @var SignalSlotDispatcher + */ + protected $signalSlotDispatcher; + + public function __construct(SignalSlotDispatcher $signalSlotDispatcher) + { + $this->signalSlotDispatcher = $signalSlotDispatcher; + } + + public function afterRequestDispatched(AfterRequestDispatchedEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + Dispatcher::class, + 'afterRequestDispatch', + [$event->getRequest(), $event->getResponse()] + ); + } + + public function beforeCallActionMethod(BeforeActionCallEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + ActionController::class, + 'beforeCallActionMethod', + [ + $event->getControllerClassName(), + $event->getActionMethodName(), + $event->getPreparedArguments() + ] + ); + } + + public function afterDataMappedForObject(AfterObjectThawedEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + DataMapper::class, + 'afterMappingSingleRow', + [ + $event->getObject() + ] + ); + } + + public function emitBeforeGettingObjectDataSignal(ModifyQueryBeforeFetchingObjectDataEvent $event): void + { + $signalArguments = $this->signalSlotDispatcher->dispatch( + Backend::class, + 'beforeGettingObjectData', + [ + $event->getQuery() + ] + ); + $event->setQuery($signalArguments[0]); + } + + public function emitAfterGettingObjectDataSignal(ModifyResultAfterFetchingObjectDataEvent $event): void + { + $signalArguments = $this->signalSlotDispatcher->dispatch( + Backend::class, + 'afterGettingObjectData', + [$event->getQuery(), $event->getResult()] + ); + $event->setResult($signalArguments[1]); + } + + public function emitEndInsertObjectSignal(EntityFinalizedAfterPersistenceEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + Backend::class, + 'endInsertObject', + [ + $event->getObject() + ] + ); + } + + public function emitAfterInsertObjectSignal(EntityAddedToPersistenceEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + Backend::class, + 'afterInsertObject', + [ + $event->getObject() + ] + ); + } + + public function emitAfterUpdateObjectSignal(EntityUpdatedInPersistenceEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + Backend::class, + 'afterUpdateObject', + [ + $event->getObject() + ] + ); + } + + public function emitAfterPersistObjectSignal(EntityPersistedEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + Backend::class, + 'afterPersistObject', + [ + $event->getObject() + ] + ); + } + + public function emitAfterRemoveObjectSignal(EntityRemovedFromPersistenceEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + Backend::class, + 'afterRemoveObject', + [ + $event->getObject() + ] + ); + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Mvc/AfterRequestDispatchedEvent.php b/typo3/sysext/extbase/Classes/Event/Mvc/AfterRequestDispatchedEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..ed54e9bc04bf92584af3cb3cabfff67c89ef809f --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Mvc/AfterRequestDispatchedEvent.php @@ -0,0 +1,58 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Mvc; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\Mvc\RequestInterface; +use TYPO3\CMS\Extbase\Mvc\ResponseInterface; + +/** + * Event which is fired after the dispatcher has successfully dispatched a request to a controller/action. + */ +final class AfterRequestDispatchedEvent +{ + /** + * @var RequestInterface + */ + private $request; + + /** + * @var ResponseInterface + */ + private $response; + + public function __construct(RequestInterface $request, ResponseInterface $response) + { + $this->request = $request; + $this->response = $response; + } + + /** + * @return RequestInterface + */ + public function getRequest(): RequestInterface + { + return $this->request; + } + + /** + * @return ResponseInterface + */ + public function getResponse(): ResponseInterface + { + return $this->response; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Mvc/BeforeActionCallEvent.php b/typo3/sysext/extbase/Classes/Event/Mvc/BeforeActionCallEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..28da5277c621768c9d6654d8cc4877dbc4b69394 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Mvc/BeforeActionCallEvent.php @@ -0,0 +1,61 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Mvc; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * Event that is triggered before any Extbase Action is called within the ActionController or one + * of its subclasses. + */ +final class BeforeActionCallEvent +{ + /** + * @var string + */ + private $controllerClassName; + + /** + * @var string + */ + private $actionMethodName; + + /** + * @var array + */ + private $preparedArguments; + + public function __construct(string $controllerClassName, string $actionMethodName, array $preparedArguments) + { + $this->controllerClassName = $controllerClassName; + $this->actionMethodName = $actionMethodName; + $this->preparedArguments = $preparedArguments; + } + + public function getControllerClassName(): string + { + return $this->controllerClassName; + } + + public function getActionMethodName(): string + { + return $this->actionMethodName; + } + + public function getPreparedArguments(): array + { + return $this->preparedArguments; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Persistence/AfterObjectThawedEvent.php b/typo3/sysext/extbase/Classes/Event/Persistence/AfterObjectThawedEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..ca188549a31927bc38c74217078e3f307eb4b48e --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Persistence/AfterObjectThawedEvent.php @@ -0,0 +1,51 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Persistence; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; + +/** + * Allows to modify values when creating domain objects. + */ +final class AfterObjectThawedEvent +{ + /** + * @var DomainObjectInterface + */ + private $mappedObject; + + /** + * @var array + */ + private $record; + + public function __construct(DomainObjectInterface $mappedObject, array $record) + { + $this->mappedObject = $mappedObject; + $this->record = $record; + } + + public function getObject(): DomainObjectInterface + { + return $this->mappedObject; + } + + public function getRecord(): array + { + return $this->record; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Persistence/EntityAddedToPersistenceEvent.php b/typo3/sysext/extbase/Classes/Event/Persistence/EntityAddedToPersistenceEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..cb4152e2b6ac69f5b3a7522e55d9b451397a5d17 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Persistence/EntityAddedToPersistenceEvent.php @@ -0,0 +1,41 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Persistence; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; + +/** + * Event which is fired after an object/entity was sent to persistence layer to be added, + * but before updating the reference index and current session. + */ +final class EntityAddedToPersistenceEvent +{ + /** + * @var DomainObjectInterface + */ + private $persistedObject; + + public function __construct(DomainObjectInterface $persistedObject) + { + $this->persistedObject = $persistedObject; + } + + public function getObject(): DomainObjectInterface + { + return $this->persistedObject; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Persistence/EntityFinalizedAfterPersistenceEvent.php b/typo3/sysext/extbase/Classes/Event/Persistence/EntityFinalizedAfterPersistenceEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..4f41d495c9352cd821debda97049cfce3e33568b --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Persistence/EntityFinalizedAfterPersistenceEvent.php @@ -0,0 +1,41 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Persistence; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; + +/** + * Event which is fired after an object/entity was sent to persistence layer to be added + * including update of reference index and current session. + */ +final class EntityFinalizedAfterPersistenceEvent +{ + /** + * @var DomainObjectInterface + */ + private $persistedObject; + + public function __construct(DomainObjectInterface $persistedObject) + { + $this->persistedObject = $persistedObject; + } + + public function getObject(): DomainObjectInterface + { + return $this->persistedObject; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Persistence/EntityPersistedEvent.php b/typo3/sysext/extbase/Classes/Event/Persistence/EntityPersistedEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..ee6f608fbd3e02f4c7ce1b9490ebecd7ced39c95 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Persistence/EntityPersistedEvent.php @@ -0,0 +1,40 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Persistence; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; + +/** + * Event which is fired after an object was pushed to the storage backend + */ +final class EntityPersistedEvent +{ + /** + * @var DomainObjectInterface + */ + private $persistedObject; + + public function __construct(DomainObjectInterface $persistedObject) + { + $this->persistedObject = $persistedObject; + } + + public function getObject(): DomainObjectInterface + { + return $this->persistedObject; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Persistence/EntityRemovedFromPersistenceEvent.php b/typo3/sysext/extbase/Classes/Event/Persistence/EntityRemovedFromPersistenceEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..4c57b57567f13499a98b1b9b89f8926a68c63b7f --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Persistence/EntityRemovedFromPersistenceEvent.php @@ -0,0 +1,40 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Persistence; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; + +/** + * Event which is fired after an object/entity was sent to persistence layer to be removed. + */ +final class EntityRemovedFromPersistenceEvent +{ + /** + * @var DomainObjectInterface + */ + private $persistedObject; + + public function __construct(DomainObjectInterface $persistedObject) + { + $this->persistedObject = $persistedObject; + } + + public function getObject(): DomainObjectInterface + { + return $this->persistedObject; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Persistence/EntityUpdatedInPersistenceEvent.php b/typo3/sysext/extbase/Classes/Event/Persistence/EntityUpdatedInPersistenceEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..eb79bd347460caf12d679893e5f7905c0048bad6 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Persistence/EntityUpdatedInPersistenceEvent.php @@ -0,0 +1,40 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Persistence; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; + +/** + * Event which is fired after an object/entity was sent to persistence layer to be updated. + */ +final class EntityUpdatedInPersistenceEvent +{ + /** + * @var DomainObjectInterface + */ + private $persistedObject; + + public function __construct(DomainObjectInterface $persistedObject) + { + $this->persistedObject = $persistedObject; + } + + public function getObject(): DomainObjectInterface + { + return $this->persistedObject; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Persistence/ModifyQueryBeforeFetchingObjectDataEvent.php b/typo3/sysext/extbase/Classes/Event/Persistence/ModifyQueryBeforeFetchingObjectDataEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..c76fe414cfd754836e214d5ceacaac02a6b9ceb6 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Persistence/ModifyQueryBeforeFetchingObjectDataEvent.php @@ -0,0 +1,45 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Persistence; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\Persistence\QueryInterface; + +/** + * Event which is fired before the storage backend is asked for results from a given query. + */ +final class ModifyQueryBeforeFetchingObjectDataEvent +{ + /** + * @var QueryInterface + */ + private $query; + + public function __construct(QueryInterface $query) + { + $this->query = $query; + } + + public function getQuery(): QueryInterface + { + return $this->query; + } + + public function setQuery(QueryInterface $query): void + { + $this->query = $query; + } +} diff --git a/typo3/sysext/extbase/Classes/Event/Persistence/ModifyResultAfterFetchingObjectDataEvent.php b/typo3/sysext/extbase/Classes/Event/Persistence/ModifyResultAfterFetchingObjectDataEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..7d587bf8458c8e44c83ea6dc926a254a03017373 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Event/Persistence/ModifyResultAfterFetchingObjectDataEvent.php @@ -0,0 +1,56 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\Extbase\Event\Persistence; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Extbase\Persistence\QueryInterface; + +/** + * Event which is fired after the storage backend has pulled results from a given query. + */ +final class ModifyResultAfterFetchingObjectDataEvent +{ + /** + * @var QueryInterface + */ + private $query; + + /** + * @var array + */ + private $result; + + public function __construct(QueryInterface $query, array $result) + { + $this->query = $query; + $this->result = $result; + } + + public function getQuery(): QueryInterface + { + return $this->query; + } + + public function getResult(): array + { + return $this->result; + } + + public function setResult(array $result): void + { + $this->result = $result; + } +} diff --git a/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php b/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php index 757040d5bf13c1833a1fbce7d0391b082f993de6..28b0643531421dd4119f83ea145cbb5d53740934 100644 --- a/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php +++ b/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php @@ -14,11 +14,13 @@ namespace TYPO3\CMS\Extbase\Mvc\Controller; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Page\PageRenderer; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; +use TYPO3\CMS\Extbase\Event\Mvc\BeforeActionCallEvent; use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException; use TYPO3\CMS\Extbase\Mvc\View\ViewInterface; use TYPO3\CMS\Extbase\Mvc\Web\ReferringRequest; @@ -81,6 +83,11 @@ class ActionController implements ControllerInterface */ protected $mvcPropertyMappingConfigurationService; + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + /** * The current request. * @@ -127,6 +134,11 @@ class ActionController implements ControllerInterface $this->mvcPropertyMappingConfigurationService = $mvcPropertyMappingConfigurationService; } + public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher): void + { + $this->eventDispatcher = $eventDispatcher; + } + /** * Handles a request. The result output is returned by altering the given response. * @@ -321,7 +333,7 @@ class ActionController implements ControllerInterface } $validationResult = $this->arguments->validate(); if (!$validationResult->hasErrors()) { - $this->emitBeforeCallActionMethodSignal($preparedArguments); + $this->eventDispatcher->dispatch(new BeforeActionCallEvent(static::class, $this->actionMethodName, $preparedArguments)); $actionResult = $this->{$this->actionMethodName}(...$preparedArguments); } else { $actionResult = $this->{$this->errorMethodName}(); @@ -343,6 +355,10 @@ class ActionController implements ControllerInterface */ protected function emitBeforeCallActionMethodSignal(array $preparedArguments) { + trigger_error( + __METHOD__ . ' is deprecated and will be removed in version 11.0 - use PSR-14 events instead.', + E_USER_DEPRECATED + ); $this->signalSlotDispatcher->dispatch(__CLASS__, 'beforeCallActionMethod', [static::class, $this->actionMethodName, $preparedArguments]); } diff --git a/typo3/sysext/extbase/Classes/Mvc/Dispatcher.php b/typo3/sysext/extbase/Classes/Mvc/Dispatcher.php index 684c9973e05d56eaf39bfabb7d01ce9a5ec1839d..f1bf0ceeaf06b9c084d7178bcb86922ee3fc603f 100644 --- a/typo3/sysext/extbase/Classes/Mvc/Dispatcher.php +++ b/typo3/sysext/extbase/Classes/Mvc/Dispatcher.php @@ -1,10 +1,6 @@ <?php namespace TYPO3\CMS\Extbase\Mvc; -use Psr\Container\ContainerInterface; -use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; -use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher; - /* * This file is part of the TYPO3 CMS project. * @@ -18,12 +14,18 @@ use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher; * The TYPO3 project - inspiring people to share! */ +use Psr\Container\ContainerInterface; +use Psr\EventDispatcher\EventDispatcherInterface; +use TYPO3\CMS\Core\SingletonInterface; +use TYPO3\CMS\Extbase\Event\Mvc\AfterRequestDispatchedEvent; +use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; + /** * Dispatches requests to the controller which was specified by the request and * returns the response the controller generated. * @internal only to be used within Extbase, not part of TYPO3 Core API. */ -class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface +class Dispatcher implements SingletonInterface { /** * @var ObjectManagerInterface A reference to the object manager @@ -36,9 +38,9 @@ class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface private $container; /** - * @var SignalSlotDispatcher + * @var EventDispatcherInterface */ - protected $signalSlotDispatcher; + protected $eventDispatcher; /** * @var array @@ -50,61 +52,51 @@ class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface * * @param ObjectManagerInterface $objectManager A reference to the object manager * @param ContainerInterface $container - * @param SignalSlotDispatcher $signalSlotDispatcher + * @param EventDispatcherInterface $eventDispatcher */ public function __construct( ObjectManagerInterface $objectManager, ContainerInterface $container, - SignalSlotDispatcher $signalSlotDispatcher + EventDispatcherInterface $eventDispatcher ) { $this->objectManager = $objectManager; $this->container = $container; - $this->signalSlotDispatcher = $signalSlotDispatcher; + $this->eventDispatcher = $eventDispatcher; } /** * Dispatches a request to a controller and initializes the security framework. * - * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request to dispatch - * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, to be modified by the controller + * @param RequestInterface $request The request to dispatch + * @param ResponseInterface $response The response, to be modified by the controller * @throws Exception\InfiniteLoopException */ - public function dispatch(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response) + public function dispatch(RequestInterface $request, ResponseInterface $response) { $dispatchLoopCount = 0; while (!$request->isDispatched()) { if ($dispatchLoopCount++ > 99) { - throw new \TYPO3\CMS\Extbase\Mvc\Exception\InfiniteLoopException('Could not ultimately dispatch the request after ' . $dispatchLoopCount . ' iterations. Most probably, a @' . \TYPO3\CMS\Extbase\Annotation\IgnoreValidation::class . ' annotation is missing on re-displaying a form with validation errors.', 1217839467); + throw new Exception\InfiniteLoopException('Could not ultimately dispatch the request after ' . $dispatchLoopCount . ' iterations. Most probably, a @' . \TYPO3\CMS\Extbase\Annotation\IgnoreValidation::class . ' annotation is missing on re-displaying a form with validation errors.', 1217839467); } $controller = $this->resolveController($request); try { $controller->processRequest($request, $response); - } catch (\TYPO3\CMS\Extbase\Mvc\Exception\StopActionException $ignoredException) { + } catch (Exception\StopActionException $ignoredException) { } } - $this->emitAfterRequestDispatchSignal($request, $response); - } - /** - * Emits a signal after a request was dispatched - * - * @param RequestInterface $request - * @param ResponseInterface $response - */ - protected function emitAfterRequestDispatchSignal(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterRequestDispatch', [$request, $response]); + $this->eventDispatcher->dispatch(new AfterRequestDispatchedEvent($request, $response)); } /** * Finds and instantiates a controller that matches the current request. * If no controller can be found, an instance of NotFoundControllerInterface is returned. * - * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request to dispatch + * @param RequestInterface $request The request to dispatch + * @return Controller\ControllerInterface * @throws Exception\InvalidControllerException - * @return \TYPO3\CMS\Extbase\Mvc\Controller\ControllerInterface */ - protected function resolveController(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request) + protected function resolveController(RequestInterface $request) { $controllerObjectName = $request->getControllerObjectName(); if ($this->container->has($controllerObjectName)) { @@ -112,8 +104,8 @@ class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface } else { $controller = $this->objectManager->get($controllerObjectName); } - if (!$controller instanceof \TYPO3\CMS\Extbase\Mvc\Controller\ControllerInterface) { - throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidControllerException( + if (!$controller instanceof Controller\ControllerInterface) { + throw new Exception\InvalidControllerException( 'Invalid controller "' . $request->getControllerObjectName() . '". The controller must implement the TYPO3\\CMS\\Extbase\\Mvc\\Controller\\ControllerInterface.', 1476109646 ); diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php index e95497d80029f5d3f75450d4b4b82e40222830be..7c5baa99b9e695f31104838721b8c1cd3f23205a 100644 --- a/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php +++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php @@ -14,8 +14,16 @@ namespace TYPO3\CMS\Extbase\Persistence\Generic; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; +use TYPO3\CMS\Extbase\Event\Persistence\EntityAddedToPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityFinalizedAfterPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\ModifyQueryBeforeFetchingObjectDataEvent; +use TYPO3\CMS\Extbase\Event\Persistence\ModifyResultAfterFetchingObjectDataEvent; use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap; use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper; @@ -95,6 +103,11 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface */ protected $signalSlotDispatcher; + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + /** * Constructs the backend * @@ -104,7 +117,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface * @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory * @param \TYPO3\CMS\Extbase\Persistence\Generic\Storage\BackendInterface $storageBackend * @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory - * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher + * @param EventDispatcherInterface $eventDispatcher */ public function __construct( \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager, @@ -113,7 +126,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory, \TYPO3\CMS\Extbase\Persistence\Generic\Storage\BackendInterface $storageBackend, \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory, - \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher + EventDispatcherInterface $eventDispatcher ) { $this->configurationManager = $configurationManager; $this->session = $session; @@ -121,7 +134,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface $this->qomFactory = $qomFactory; $this->storageBackend = $storageBackend; $this->dataMapFactory = $dataMapFactory; - $this->signalSlotDispatcher = $signalSlotDispatcher; + $this->eventDispatcher = $eventDispatcher; $this->referenceIndex = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ReferenceIndex::class); $this->referenceIndex->enableRuntimeCache(); @@ -187,35 +200,13 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface */ public function getObjectDataByQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query) { - $query = $this->emitBeforeGettingObjectDataSignal($query); + $event = new ModifyQueryBeforeFetchingObjectDataEvent($query); + $this->eventDispatcher->dispatch($event); + $query = $event->getQuery(); $result = $this->storageBackend->getObjectDataByQuery($query); - $result = $this->emitAfterGettingObjectDataSignal($query, $result); - return $result; - } - - /** - * Emits a signal before object data is fetched - * - * @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query - * @return \TYPO3\CMS\Extbase\Persistence\QueryInterface Modified query - */ - protected function emitBeforeGettingObjectDataSignal(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query) - { - $signalArguments = $this->signalSlotDispatcher->dispatch(__CLASS__, 'beforeGettingObjectData', [$query]); - return $signalArguments[0]; - } - - /** - * Emits a signal after object data is fetched - * - * @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query - * @param array $result - * @return array Modified result - */ - protected function emitAfterGettingObjectDataSignal(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query, array $result) - { - $signalArguments = $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterGettingObjectData', [$query, $result]); - return $signalArguments[1]; + $event = new ModifyResultAfterFetchingObjectDataEvent($query, $result); + $this->eventDispatcher->dispatch($event); + return $event->getResult(); } /** @@ -378,7 +369,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface foreach ($queue as $queuedObject) { $this->persistObject($queuedObject); } - $this->emitAfterPersistObjectSignal($object); + $this->eventDispatcher->dispatch(new EntityPersistedEvent($object)); } /** @@ -671,7 +662,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface $object->_setProperty('uid', (int)$uid); $object->setPid((int)$row['pid']); if ((int)$uid >= 1) { - $this->emitAfterInsertObjectSignal($object); + $this->eventDispatcher->dispatch(new EntityAddedToPersistenceEvent($object)); } $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK); if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') { @@ -679,31 +670,10 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface } $this->session->registerObject($object, $uid); if ((int)$uid >= 1) { - $this->emitEndInsertObjectSignal($object); + $this->eventDispatcher->dispatch(new EntityFinalizedAfterPersistenceEvent($object)); } } - /** - * Emits a signal after an object was added to the storage - * - * @param DomainObjectInterface $object - */ - protected function emitAfterInsertObjectSignal(DomainObjectInterface $object) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterInsertObject', [$object]); - } - - /** - * Emits a signal after an object was registered in persistence session - * This signal replaces the afterInsertObject signal which is now deprecated - * - * @param DomainObjectInterface $object - */ - protected function emitEndInsertObjectSignal(DomainObjectInterface $object) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'endInsertObject', [$object]); - } - /** * Tests, if the given Value Object already exists in the storage backend and if so, it returns the uid. * @@ -906,7 +876,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface } } $this->storageBackend->updateRow($dataMap->getTableName(), $row); - $this->emitAfterUpdateObjectSignal($object); + $this->eventDispatcher->dispatch(new EntityUpdatedInPersistenceEvent($object)); $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK); if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') { @@ -915,26 +885,6 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface return true; } - /** - * Emits a signal after an object was updated in storage - * - * @param DomainObjectInterface $object - */ - protected function emitAfterUpdateObjectSignal(DomainObjectInterface $object) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterUpdateObject', [$object]); - } - - /** - * Emits a signal after an object was persisted - * - * @param DomainObjectInterface $object - */ - protected function emitAfterPersistObjectSignal(DomainObjectInterface $object) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterPersistObject', [$object]); - } - /** * Adds common database fields to a row * @@ -1006,7 +956,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface } else { $this->storageBackend->removeRow($tableName, ['uid' => $object->getUid()]); } - $this->emitAfterRemoveObjectSignal($object); + $this->eventDispatcher->dispatch(new EntityRemovedFromPersistenceEvent($object)); $this->removeRelatedObjects($object); $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK); @@ -1015,16 +965,6 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface } } - /** - * Emits a signal after an object was removed from storage - * - * @param DomainObjectInterface $object - */ - protected function emitAfterRemoveObjectSignal(DomainObjectInterface $object) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterRemoveObject', [$object]); - } - /** * Remove related objects * diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php index 76ca311123ab04b3e972bfab9bdbf479ec1caaa2..cd00833c2d8ced381ec765affd7462d027d6dfe1 100644 --- a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php +++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php @@ -14,8 +14,10 @@ namespace TYPO3\CMS\Extbase\Persistence\Generic\Mapper; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Core\Database\Query\QueryHelper; use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; +use TYPO3\CMS\Extbase\Event\Persistence\AfterObjectThawedEvent; use TYPO3\CMS\Extbase\Object\Exception\CannotReconstituteObjectException; use TYPO3\CMS\Extbase\Persistence; use TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException; @@ -60,9 +62,9 @@ class DataMapper protected $objectManager; /** - * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher + * @var EventDispatcherInterface */ - protected $signalSlotDispatcher; + protected $eventDispatcher; /** * @var ?QueryInterface @@ -77,7 +79,7 @@ class DataMapper * @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory * @param \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager - * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher + * @param EventDispatcherInterface $eventDispatcher * @param QueryInterface|null $query */ public function __construct( @@ -87,7 +89,7 @@ class DataMapper \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory, \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory, \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager, - \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher, + EventDispatcherInterface $eventDispatcher, ?QueryInterface $query = null ) { $this->query = $query; @@ -97,7 +99,7 @@ class DataMapper $this->dataMapFactory = $dataMapFactory; $this->queryFactory = $queryFactory; $this->objectManager = $objectManager; - $this->signalSlotDispatcher = $signalSlotDispatcher; + $this->eventDispatcher = $eventDispatcher; if ($query !== null) { trigger_error( @@ -170,29 +172,20 @@ class DataMapper $object = $this->createEmptyObject($className); $this->persistenceSession->registerObject($object, $row['uid']); $this->thawProperties($object, $row); - $this->emitAfterMappingSingleRow($object); + $event = new AfterObjectThawedEvent($object, $row); + $this->eventDispatcher->dispatch($event); $object->_memorizeCleanState(); $this->persistenceSession->registerReconstitutedEntity($object); } return $object; } - /** - * Emits a signal after mapping a single row. - * - * @param DomainObjectInterface $object The mapped object - */ - protected function emitAfterMappingSingleRow(DomainObjectInterface $object) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterMappingSingleRow', [$object]); - } - /** * Creates a skeleton of the specified object * * @param string $className Name of the class to create a skeleton for * @throws CannotReconstituteObjectException - * @return object The object skeleton + * @return DomainObjectInterface The object skeleton */ protected function createEmptyObject($className) { diff --git a/typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php b/typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php index 5651ca4f6241dc857f3f1373f705ddc8aa2bc332..7010bbda7e3585abb7ab47f27aecd00792ef76ec 100644 --- a/typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php +++ b/typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php @@ -85,7 +85,20 @@ use TYPO3\CMS\Core\Resource\Service\FileProcessingService; use TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent; use TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; +use TYPO3\CMS\Extbase\Event\Mvc\AfterRequestDispatchedEvent; +use TYPO3\CMS\Extbase\Event\Mvc\BeforeActionCallEvent; +use TYPO3\CMS\Extbase\Event\Persistence\AfterObjectThawedEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityAddedToPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityFinalizedAfterPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent; +use TYPO3\CMS\Extbase\Event\Persistence\ModifyQueryBeforeFetchingObjectDataEvent; +use TYPO3\CMS\Extbase\Event\Persistence\ModifyResultAfterFetchingObjectDataEvent; +use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; +use TYPO3\CMS\Extbase\Persistence\Generic\Backend; +use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper; /** * A dispatcher which dispatches signals by calling its registered slot methods @@ -196,6 +209,24 @@ class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface UsernamePasswordLoginProvider::class => [ 'getPageRenderer' => ModifyPageLayoutOnLoginProviderSelectionEvent::class ], + \TYPO3\CMS\Extbase\Mvc\Dispatcher::class => [ + 'afterRequestDispatch' => AfterRequestDispatchedEvent::class + ], + ActionController::class => [ + 'beforeCallActionMethod' => BeforeActionCallEvent::class + ], + DataMapper::class => [ + 'afterMappingSingleRow' => AfterObjectThawedEvent::class + ], + Backend::class => [ + 'beforeGettingObjectData' => ModifyQueryBeforeFetchingObjectDataEvent::class, + 'afterGettingObjectData' => ModifyResultAfterFetchingObjectDataEvent::class, + 'endInsertObject' => EntityFinalizedAfterPersistenceEvent::class, + 'afterInsertObject' => EntityAddedToPersistenceEvent::class, + 'afterUpdateObject' => EntityUpdatedInPersistenceEvent::class, + 'afterPersistObject' => EntityPersistedEvent::class, + 'afterRemoveObject' => EntityRemovedFromPersistenceEvent::class + ], // Strings are used here on purpose for all non-required system extensions. Do not change to // Fqn::class *unless* you also declare each and every extension whose classes are listed // here as explicit and mandatory dependencies of EXT:extbase. diff --git a/typo3/sysext/extbase/Configuration/Services.yaml b/typo3/sysext/extbase/Configuration/Services.yaml index 691376f62dab5d24b8f361c52ac09fa6796ddc4c..e393761fbb7b76e199c62248e54bb51ecee8f4e8 100644 --- a/typo3/sysext/extbase/Configuration/Services.yaml +++ b/typo3/sysext/extbase/Configuration/Services.yaml @@ -39,3 +39,47 @@ services: class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache'] arguments: ['extbase'] + + # Listener for old Signal Slots + TYPO3\CMS\Extbase\Compatibility\SlotReplacement: + tags: + - name: event.listener + identifier: 'legacy-slot' + method: 'afterRequestDispatched' + event: TYPO3\CMS\Extbase\Event\Mvc\AfterRequestDispatchedEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'beforeCallActionMethod' + event: TYPO3\CMS\Extbase\Event\Mvc\BeforeActionCallEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'afterDataMappedForObject' + event: TYPO3\CMS\Extbase\Event\Persistence\AfterObjectThawedEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitBeforeGettingObjectDataSignal' + event: TYPO3\CMS\Extbase\Event\Persistence\ModifyQueryBeforeFetchingObjectDataEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitAfterGettingObjectDataSignal' + event: TYPO3\CMS\Extbase\Event\Persistence\ModifyResultAfterFetchingObjectDataEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitEndInsertObjectSignal' + event: TYPO3\CMS\Extbase\Event\Persistence\EntityFinalizedAfterPersistenceEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitAfterInsertObjectSignal' + event: TYPO3\CMS\Extbase\Event\Persistence\EntityAddedToPersistenceEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitAfterUpdateObjectSignal' + event: TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitAfterRemoveObjectSignal' + event: TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitAfterPersistObjectSignal' + event: TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent diff --git a/typo3/sysext/extbase/Tests/Unit/Persistence/Generic/Mapper/DataMapperTest.php b/typo3/sysext/extbase/Tests/Unit/Persistence/Generic/Mapper/DataMapperTest.php index 7c0ff5574dd9dcd0dc06ddcf2c77d0291b0a0c0b..4d7b9997a82edc121fb17b0420b220f860aca03f 100644 --- a/typo3/sysext/extbase/Tests/Unit/Persistence/Generic/Mapper/DataMapperTest.php +++ b/typo3/sysext/extbase/Tests/Unit/Persistence/Generic/Mapper/DataMapperTest.php @@ -15,6 +15,7 @@ namespace TYPO3\CMS\Extbase\Tests\Unit\Persistence\Generic\Mapper; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface; use TYPO3\CMS\Extbase\Object\Container\Container; use TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException; @@ -50,7 +51,7 @@ class DataMapperTest extends UnitTestCase $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory::class), $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface::class), $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class), - $this->createMock(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class), + $this->createMock(EventDispatcherInterface::class), ]) ->setMethods(['mapSingleRow', 'getTargetType']) ->getMock(); @@ -86,7 +87,7 @@ class DataMapperTest extends UnitTestCase $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory::class), $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface::class), $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class), - $this->createMock(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class), + $this->createMock(EventDispatcherInterface::class), ] ); @@ -142,7 +143,7 @@ class DataMapperTest extends UnitTestCase $dataMapFactory, $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface::class), $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class), - $this->createMock(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class), + $this->createMock(EventDispatcherInterface::class), ] ); $dataMapper->_call('thawProperties', $object, $row); @@ -278,7 +279,7 @@ class DataMapperTest extends UnitTestCase $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory::class), $this->createMock(\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface::class), $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class), - $this->createMock(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class), + $this->createMock(EventDispatcherInterface::class), ] ); $dataMapper->expects(self::any())->method('getDataMap')->willReturn($dataMap); diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php index 2152ad40f4e3bcdb3ffaab4054bfc502ba58bf82..060b33fe2866e3f30324cb6c92df81c2ec9d239c 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php @@ -4399,4 +4399,11 @@ return [ 'Important-90020-LegacyBasicFileUtilityAndExtendedFileUtilityClassesMarkedAsInternal.rst', ], ], + 'TYPO3\CMS\Extbase\Mvc\Controller\ActionController->emitBeforeCallActionMethodSignal' => [ + 'numberOfMandatoryArguments' => 1, + 'maximumNumberOfArguments' => 1, + 'restFiles' => [ + 'Deprecation-89870-NewPSR-14EventsForExtbase-relatedSignals.rst', + ], + ] ];