diff --git a/typo3/sysext/core/Documentation/Changelog/12.2/Feature-99430-AddEventAfterRecordPublishingInWorkspaces.rst b/typo3/sysext/core/Documentation/Changelog/12.2/Feature-99430-AddEventAfterRecordPublishingInWorkspaces.rst new file mode 100644 index 0000000000000000000000000000000000000000..8c4e058e52d1045396533bddc9bf8849ab85e496 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/12.2/Feature-99430-AddEventAfterRecordPublishingInWorkspaces.rst @@ -0,0 +1,58 @@ +.. include:: /Includes.rst.txt + +.. _feature-99430-1672129914: + +================================================================= +Feature: #99430 - Add event after record publishing in workspaces +================================================================= + +See :issue:`99430` + +Description +=========== + +A new PSR-14 event :php:`\TYPO3\CMS\Workspaces\Event\AfterRecordPublishedEvent` +has been added to allow extension developers to react on record publishing +in workspaces. + +The new event is fired after a record has been published in a workspace and +provides the following information: + +- :php:`getTable()`: The records' table name +- :php:`getRecordId()`: The records' uid +- :php:`getWorkspaceId()`: The workspace the record has been published in + +Example +======= + +Registration of the :php:`AfterRecordPublishedEvent` in your extensions' +:file:`Services.yaml`: + +.. code-block:: yaml + + MyVendor\MyPackage\Workspaces\MyEventListener: + tags: + - name: event.listener + identifier: 'my-package/after-record-published' + +The corresponding event listener class: + +.. code-block:: php + + use TYPO3\CMS\Workspaces\Event\AfterRecordPublishedEvent; + + class MyEventListener { + + public function __invoke(AfterRecordPublishedEvent $event): void + { + // Do your magic here + } + } + +Impact +====== + +With the new PSR-14 :php:`AfterRecordPublishedEvent` it is possible to +execute custom functionality after a record has been published in a workspace. + +.. index:: PHP-API, ext:workspaces diff --git a/typo3/sysext/workspaces/Classes/Event/AfterRecordPublishedEvent.php b/typo3/sysext/workspaces/Classes/Event/AfterRecordPublishedEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..684b3a78ab545c6a70f37d970147af3221809afc --- /dev/null +++ b/typo3/sysext/workspaces/Classes/Event/AfterRecordPublishedEvent.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +/* + * 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! + */ + +namespace TYPO3\CMS\Workspaces\Event; + +/** + * Event that is fired after a record has been published ina workspace. + */ +final class AfterRecordPublishedEvent +{ + public function __construct( + private readonly string $table, + private readonly int $recordId, + private readonly int $workspaceId, + ) { + } + + public function getTable(): string + { + return $this->table; + } + + public function getRecordId(): int + { + return $this->recordId; + } + + public function getWorkspaceId(): int + { + return $this->workspaceId; + } +} diff --git a/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php b/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php index e9050c14cf7ecebf0c96ea516035d6beb722f5c2..9841f5b06a3870e8b70d40810e0905042f2c8e73 100644 --- a/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php +++ b/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php @@ -16,6 +16,7 @@ namespace TYPO3\CMS\Workspaces\Hook; use Doctrine\DBAL\Exception as DBALException; +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Cache\CacheManager; @@ -34,6 +35,7 @@ use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Versioning\VersionState; use TYPO3\CMS\Workspaces\DataHandler\CommandMap; +use TYPO3\CMS\Workspaces\Event\AfterRecordPublishedEvent; use TYPO3\CMS\Workspaces\Notification\StageChangeNotification; use TYPO3\CMS\Workspaces\Service\StagesService; use TYPO3\CMS\Workspaces\Service\WorkspaceService; @@ -45,6 +47,10 @@ use TYPO3\CMS\Workspaces\Service\WorkspaceService; */ class DataHandlerHook { + public function __construct(private readonly EventDispatcherInterface $eventDispatcher) + { + } + /** * For accumulating information about workspace stages raised * on elements so a single mail is sent as notification. @@ -709,6 +715,7 @@ class DataHandlerHook $dataHandler->deleteEl($table, $id, true); $dataHandler->BE_USER->workspace = $currentUserWorkspace; } + $this->eventDispatcher->dispatch(new AfterRecordPublishedEvent($table, $id, $workspaceId)); $dataHandler->log($table, $id, DatabaseAction::PUBLISH, 0, SystemLogErrorClassification::MESSAGE, 'Publishing successful for table "{table}" uid {liveId}=>{versionId}', -1, ['table' => $table, 'versionId' => $swapWith, 'liveId' => $id], $dataHandler->eventPid($table, $id, $swapVersion['pid'])); // Set log entry for live record: @@ -945,6 +952,7 @@ class DataHandlerHook if ($dataHandler->enableLogging) { $dataHandler->log($table, $id, DatabaseAction::PUBLISH, 0, SystemLogErrorClassification::MESSAGE, 'Publishing successful for table "{table}" uid {uid} (new record)', -1, ['table' => $table, 'uid' => $id], $dataHandler->eventPid($table, $id, $newRecordInWorkspace['pid'])); } + $this->eventDispatcher->dispatch(new AfterRecordPublishedEvent($table, $id, $workspaceId)); // Set log entry for record $propArr = $dataHandler->getRecordPropertiesFromRow($table, $newRecordInWorkspace); diff --git a/typo3/sysext/workspaces/Configuration/Services.yaml b/typo3/sysext/workspaces/Configuration/Services.yaml index adeaa923f67045eabf6240f020d8f1622a3d3f70..1b704351ee7a9cae3a30bd16b5a2be6ad2ee8430 100644 --- a/typo3/sysext/workspaces/Configuration/Services.yaml +++ b/typo3/sysext/workspaces/Configuration/Services.yaml @@ -40,6 +40,9 @@ services: TYPO3\CMS\Workspaces\Controller\Remote\ActionHandler: public: true + TYPO3\CMS\Workspaces\Hook\DataHandlerHook: + public: true + TYPO3\CMS\Workspaces\Hook\BackendUtilityHook: tags: - name: event.listener diff --git a/typo3/sysext/workspaces/Tests/Functional/Hook/DataHandlerHookTest.php b/typo3/sysext/workspaces/Tests/Functional/Hook/DataHandlerHookTest.php index 2801856107184964f8e35776c1e4ab2a1aaa619c..a9b29f2ca4dcafcb7ff374f66245a62e9a90d744 100644 --- a/typo3/sysext/workspaces/Tests/Functional/Hook/DataHandlerHookTest.php +++ b/typo3/sysext/workspaces/Tests/Functional/Hook/DataHandlerHookTest.php @@ -17,11 +17,14 @@ declare(strict_types=1); namespace TYPO3\CMS\Workspaces\Tests\Functional\Hook; +use Symfony\Component\DependencyInjection\Container; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Context\WorkspaceAspect; use TYPO3\CMS\Core\Core\Bootstrap; +use TYPO3\CMS\Core\EventDispatcher\ListenerProvider; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Workspaces\Event\AfterRecordPublishedEvent; use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\ActionService; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; @@ -84,4 +87,39 @@ class DataHandlerHookTest extends FunctionalTestCase $this->assertCSVDataSet(__DIR__ . '/DataSet/deletingSysWorkspaceDeletesWorkspaceRecordsResult.csv'); } + + /** + * @test + */ + public function flushByTagEventIsTriggered(): void + { + $afterRecordPublishedEvent = null; + + /** @var Container $container */ + $container = $this->getContainer(); + $container->set( + 'after-record-published-event', + static function (AfterRecordPublishedEvent $event) use (&$afterRecordPublishedEvent) { + $afterRecordPublishedEvent = $event; + } + ); + + $eventListener = $container->get(ListenerProvider::class); + $eventListener->addListener(AfterRecordPublishedEvent::class, 'after-record-published-event'); + + $this->importCSVDataSet(__DIR__ . '/DataSet/deletingSysWorkspaceDeletesWorkspaceRecords.csv'); + + $workspaceId = 1; + $tableName = 'tt_content'; + $recordId = 301; + + $this->setWorkspaceId($workspaceId); + $this->actionService->modifyRecord($tableName, $recordId, ['header' => '[Translate to Dansk:] Regular Element #1 Changed']); + $this->actionService->publishRecord($tableName, $recordId); + + self::assertInstanceOf(AfterRecordPublishedEvent::class, $afterRecordPublishedEvent); + self::assertEquals($tableName, $afterRecordPublishedEvent->getTable()); + self::assertEquals($recordId, $afterRecordPublishedEvent->getRecordId()); + self::assertEquals($workspaceId, $afterRecordPublishedEvent->getWorkspaceId()); + } } diff --git a/typo3/sysext/workspaces/Tests/Unit/Event/AfterRecordPublishedEventTest.php b/typo3/sysext/workspaces/Tests/Unit/Event/AfterRecordPublishedEventTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b46cfbd2992083a760b5c30f7a2ce5a59f312419 --- /dev/null +++ b/typo3/sysext/workspaces/Tests/Unit/Event/AfterRecordPublishedEventTest.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +/* + * 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! + */ + +namespace TYPO3\CMS\Workspaces\Tests\Unit\Event; + +use TYPO3\CMS\Workspaces\Event\AfterRecordPublishedEvent; +use TYPO3\TestingFramework\Core\Unit\UnitTestCase; + +class AfterRecordPublishedEventTest extends UnitTestCase +{ + /** + * @test + */ + public function gettersReturnInitializedObjects(): void + { + $table = 'some_table'; + $recordId = 2004; + $workspaceId = 13; + + $event = new AfterRecordPublishedEvent($table, $recordId, $workspaceId); + + self::assertEquals($table, $event->getTable()); + self::assertEquals($recordId, $event->getRecordId()); + self::assertEquals($workspaceId, $event->getWorkspaceId()); + } +}