[FEATURE] Migrate various Signals to PSR-14 events in system extensions 22/62422/15
authorBenni Mack <benni@typo3.org>
Sat, 23 Nov 2019 22:36:33 +0000 (23:36 +0100)
committerSusanne Moog <look@susi.dev>
Mon, 2 Dec 2019 10:43:38 +0000 (11:43 +0100)
The following new PSR-14 events are added:

TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent
TYPO3\CMS\Backend\Authentication\Event\SwitchUserEvent
TYPO3\CMS\Backend\Controller\Event\BeforeFormEnginePageInitializedEvent
TYPO3\CMS\Backend\Controller\Event\AfterFormEnginePageInitializedEvent
TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent
TYPO3\CMS\Impexp\Event\BeforeImportEvent
TYPO3\CMS\Install\Service\Event\ModifyLanguagePackRemoteBaseUrlEvent
TYPO3\CMS\Linkvalidator\Event\BeforeRecordIsAnalyzedEvent
TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent
TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent
TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent
TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent
TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent

They replace the following "old" signals with a deprecation layer:

TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider::getPageRenderer
TYPO3\CMS\Backend\Controller\EditDocumentController::preInitAfter
TYPO3\CMS\Backend\Controller\EditDocumentController::initAfter
TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfigPreInclude
TYPO3\CMS\Beuser\Controller\BackendUserController::switchUser
TYPO3\CMS\Impexp\Utility\ImportExportUtility::afterImportExportInitialisation
TYPO3\CMS\Lang\Service\TranslationService::postProcessMirrorUrl
TYPO3\CMS\Linkvalidator\LinkAnalyzer::beforeAnalyzeRecord
TYPO3\CMS\Seo\Canonical\CanonicalGenerator::beforeGeneratingCanonical
TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_BeforeCaching
TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_PostProcesss
TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GetDataArray_PostProcesss
TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_SortDataArray_PostProcesss

Relates: #89733
Resolves: #89813
Releases: master
Change-Id: I13f2454fd8f4efb5f4c5248d0b839634b77578db
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62422
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Susanne Moog <look@susi.dev>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Susanne Moog <look@susi.dev>
48 files changed:
typo3/sysext/backend/Classes/Authentication/Event/SwitchUserEvent.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Compatibility/SlotReplacement.php
typo3/sysext/backend/Classes/Controller/EditDocumentController.php
typo3/sysext/backend/Classes/Controller/Event/AfterFormEnginePageInitializedEvent.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Controller/Event/BeforeFormEnginePageInitializedEvent.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Controller/LoginController.php
typo3/sysext/backend/Classes/LoginProvider/Event/ModifyPageLayoutOnLoginProviderSelectionEvent.php [new file with mode: 0644]
typo3/sysext/backend/Classes/LoginProvider/UsernamePasswordLoginProvider.php
typo3/sysext/backend/Classes/Utility/BackendUtility.php
typo3/sysext/backend/Configuration/Services.yaml
typo3/sysext/backend/Tests/Unit/Controller/EditDocumentControllerTest.php
typo3/sysext/backend/Tests/Unit/Utility/BackendUtilityTest.php
typo3/sysext/beuser/Classes/Compatibility/SlotReplacement.php [new file with mode: 0644]
typo3/sysext/beuser/Classes/Controller/BackendUserController.php
typo3/sysext/beuser/Configuration/Services.yaml
typo3/sysext/core/Classes/Configuration/Event/ModifyLoadedPageTsConfigEvent.php [new file with mode: 0644]
typo3/sysext/core/Classes/Configuration/Loader/PageTsConfigLoader.php
typo3/sysext/core/Configuration/Services.yaml
typo3/sysext/core/Documentation/Changelog/master/Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst
typo3/sysext/core/Documentation/Changelog/master/Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst
typo3/sysext/core/Tests/Unit/Configuration/Loader/PageTsConfigLoaderTest.php
typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php
typo3/sysext/impexp/Classes/Compatibility/SlotReplacement.php [new file with mode: 0644]
typo3/sysext/impexp/Classes/Event/BeforeImportEvent.php [new file with mode: 0644]
typo3/sysext/impexp/Classes/Utility/ImportExportUtility.php
typo3/sysext/impexp/Configuration/Services.yaml
typo3/sysext/install/Classes/Compatibility/SlotReplacement.php [new file with mode: 0644]
typo3/sysext/install/Classes/Service/Event/ModifyLanguagePackRemoteBaseUrlEvent.php [new file with mode: 0644]
typo3/sysext/install/Classes/Service/LanguagePackService.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassConstantMatcher.php
typo3/sysext/install/Configuration/Services.yaml
typo3/sysext/linkvalidator/Classes/Compatibility/SlotReplacement.php [new file with mode: 0644]
typo3/sysext/linkvalidator/Classes/Event/BeforeRecordIsAnalyzedEvent.php [new file with mode: 0644]
typo3/sysext/linkvalidator/Classes/LinkAnalyzer.php
typo3/sysext/linkvalidator/Configuration/Services.yaml
typo3/sysext/linkvalidator/Tests/Functional/LinkAnalyzerTest.php
typo3/sysext/seo/Classes/Canonical/CanonicalGenerator.php
typo3/sysext/seo/Classes/Compatibility/SlotReplacement.php [new file with mode: 0644]
typo3/sysext/seo/Classes/Event/ModifyUrlForCanonicalTagEvent.php [new file with mode: 0644]
typo3/sysext/seo/Configuration/Services.yaml
typo3/sysext/workspaces/Classes/Compatibility/SlotReplacement.php [new file with mode: 0644]
typo3/sysext/workspaces/Classes/Event/AfterCompiledCacheableDataForWorkspaceEvent.php [new file with mode: 0644]
typo3/sysext/workspaces/Classes/Event/AfterDataGeneratedForWorkspaceEvent.php [new file with mode: 0644]
typo3/sysext/workspaces/Classes/Event/GetVersionedDataEvent.php [new file with mode: 0644]
typo3/sysext/workspaces/Classes/Event/SortVersionedDataEvent.php [new file with mode: 0644]
typo3/sysext/workspaces/Classes/Service/GridDataService.php
typo3/sysext/workspaces/Configuration/Services.yaml
typo3/sysext/workspaces/Tests/Unit/Controller/Remote/RemoteServerTest.php

diff --git a/typo3/sysext/backend/Classes/Authentication/Event/SwitchUserEvent.php b/typo3/sysext/backend/Classes/Authentication/Event/SwitchUserEvent.php
new file mode 100644 (file)
index 0000000..366c907
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Backend\Authentication\Event;
+
+/*
+ * 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!
+ */
+
+/**
+ * This event is triggered when a "SU" (switch user) action has been triggered
+ */
+final class SwitchUserEvent
+{
+    /**
+     * @var string
+     */
+    private $sessionId;
+
+    /**
+     * @var array
+     */
+    private $targetUser;
+
+    /**
+     * @var array
+     */
+    private $currentUser;
+
+    public function __construct(string $sessionId, array $targetUser, array $currentUser)
+    {
+        $this->sessionId = $sessionId;
+        $this->targetUser = $targetUser;
+        $this->currentUser = $currentUser;
+    }
+
+    public function getSessionId(): string
+    {
+        return $this->sessionId;
+    }
+
+    public function getTargetUser(): array
+    {
+        return $this->targetUser;
+    }
+
+    public function getCurrentUser(): array
+    {
+        return $this->currentUser;
+    }
+}
index a0df516..088766c 100644 (file)
@@ -17,6 +17,13 @@ namespace TYPO3\CMS\Backend\Compatibility;
 
 use TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent;
 use TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem;
+use TYPO3\CMS\Backend\Controller\EditDocumentController;
+use TYPO3\CMS\Backend\Controller\Event\AfterFormEnginePageInitializedEvent;
+use TYPO3\CMS\Backend\Controller\Event\BeforeFormEnginePageInitializedEvent;
+use TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent;
+use TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent;
 use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher;
 
 /**
@@ -51,4 +58,43 @@ class SlotReplacement
             [$event->getToolbarItem()]
         );
     }
+
+    public function onLoginProviderGetPageRenderer(ModifyPageLayoutOnLoginProviderSelectionEvent $event): void
+    {
+        $this->signalSlotDispatcher->dispatch(
+            UsernamePasswordLoginProvider::class,
+            'getPageRenderer',
+            [$event->getPageRenderer()]
+        );
+    }
+
+    public function onPreInitEditDocumentController(BeforeFormEnginePageInitializedEvent $event): void
+    {
+        $this->signalSlotDispatcher->dispatch(
+            EditDocumentController::class,
+            'preInitAfter',
+            [$event->getController(), 'request' => $event->getRequest()]
+        );
+    }
+
+    public function onInitEditDocumentController(AfterFormEnginePageInitializedEvent $event): void
+    {
+        $this->signalSlotDispatcher->dispatch(
+            EditDocumentController::class,
+            'initAfter',
+            [$event->getController(), 'request' => $event->getRequest()]
+        );
+    }
+
+    public function emitGetPagesTSconfigPreIncludeSignalBackendUtility(ModifyLoadedPageTsConfigEvent $event): void
+    {
+        $rootLine = $event->getRootLine();
+        $page = end($rootLine);
+        $signalArguments = $this->signalSlotDispatcher->dispatch(
+            BackendUtility::class,
+            'getPagesTSconfigPreInclude',
+            [$event->getTsConfig(), (int)$page['uid'], $rootLine, false]
+        );
+        $event->setTsConfig($signalArguments[0]);
+    }
 }
index a4ec19d..bea6ac2 100644 (file)
@@ -15,8 +15,11 @@ namespace TYPO3\CMS\Backend\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Controller\Event\AfterFormEnginePageInitializedEvent;
+use TYPO3\CMS\Backend\Controller\Event\BeforeFormEnginePageInitializedEvent;
 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedException;
 use TYPO3\CMS\Backend\Form\Exception\DatabaseRecordException;
 use TYPO3\CMS\Backend\Form\FormDataCompiler;
@@ -51,7 +54,6 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 
 /**
  * Main backend controller almost always used if some database record is edited in the backend.
@@ -348,11 +350,6 @@ class EditDocumentController
     protected $dontStoreDocumentRef = 0;
 
     /**
-     * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
-     */
-    protected $signalSlotDispatcher;
-
-    /**
      * Stores information needed to preview the currently saved record
      *
      * @var array
@@ -381,10 +378,13 @@ class EditDocumentController
     protected $isPageInFreeTranslationMode = false;
 
     /**
-     * Constructor
+     * @var EventDispatcherInterface
      */
-    public function __construct()
+    protected $eventDispatcher;
+
+    public function __construct(EventDispatcherInterface $eventDispatcher)
     {
+        $this->eventDispatcher = $eventDispatcher;
         $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
         $this->moduleTemplate->setUiBlock(true);
         // @todo Used by TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching
@@ -489,8 +489,8 @@ class EditDocumentController
             $this->getBackendUser()->setTemporaryWorkspace($this->workspace);
         }
 
-        $this->emitFunctionAfterSignal('preInit', $request);
-
+        $event = new BeforeFormEnginePageInitializedEvent($this, $request);
+        $this->eventDispatcher->dispatch($event);
         return null;
     }
 
@@ -779,7 +779,8 @@ class EditDocumentController
         // Set context sensitive menu
         $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
 
-        $this->emitFunctionAfterSignal('init', $request);
+        $event = new AfterFormEnginePageInitializedEvent($this, $request);
+        $this->eventDispatcher->dispatch($event);
     }
 
     /**
@@ -2453,30 +2454,6 @@ class EditDocumentController
     }
 
     /**
-     * Emits a signal after a function was executed
-     *
-     * @param string $signalName
-     * @param ServerRequestInterface $request
-     */
-    protected function emitFunctionAfterSignal($signalName, ServerRequestInterface $request): void
-    {
-        $this->getSignalSlotDispatcher()->dispatch(__CLASS__, $signalName . 'After', [$this, 'request' => $request]);
-    }
-
-    /**
-     * Get the SignalSlot dispatcher
-     *
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
-     */
-    protected function getSignalSlotDispatcher()
-    {
-        if (!isset($this->signalSlotDispatcher)) {
-            $this->signalSlotDispatcher = GeneralUtility::makeInstance(Dispatcher::class);
-        }
-        return $this->signalSlotDispatcher;
-    }
-
-    /**
      * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
      */
     protected function getBackendUser()
diff --git a/typo3/sysext/backend/Classes/Controller/Event/AfterFormEnginePageInitializedEvent.php b/typo3/sysext/backend/Classes/Controller/Event/AfterFormEnginePageInitializedEvent.php
new file mode 100644 (file)
index 0000000..af5f41f
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Backend\Controller\Event;
+
+/*
+ * 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 Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Controller\EditDocumentController;
+
+/**
+ * Event to listen to after the form engine has been initialized (= all data has been persisted)
+ */
+final class AfterFormEnginePageInitializedEvent
+{
+    /**
+     * @var EditDocumentController
+     */
+    private $controller;
+
+    /**
+     * @var ServerRequestInterface
+     */
+    private $request;
+
+    public function __construct(EditDocumentController $controller, ServerRequestInterface $request)
+    {
+        $this->controller = $controller;
+        $this->request = $request;
+    }
+
+    public function getController(): EditDocumentController
+    {
+        return $this->controller;
+    }
+
+    public function getRequest(): ServerRequestInterface
+    {
+        return $this->request;
+    }
+}
diff --git a/typo3/sysext/backend/Classes/Controller/Event/BeforeFormEnginePageInitializedEvent.php b/typo3/sysext/backend/Classes/Controller/Event/BeforeFormEnginePageInitializedEvent.php
new file mode 100644 (file)
index 0000000..585fac7
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Backend\Controller\Event;
+
+/*
+ * 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 Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Controller\EditDocumentController;
+
+/**
+ * Event to listen to before the form engine has been initialized (= before all data will be persisted)
+ */
+final class BeforeFormEnginePageInitializedEvent
+{
+    /**
+     * @var EditDocumentController
+     */
+    private $controller;
+
+    /**
+     * @var ServerRequestInterface
+     */
+    private $request;
+
+    public function __construct(EditDocumentController $controller, ServerRequestInterface $request)
+    {
+        $this->controller = $controller;
+        $this->request = $request;
+    }
+
+    public function getController(): EditDocumentController
+    {
+        return $this->controller;
+    }
+
+    public function getRequest(): ServerRequestInterface
+    {
+        return $this->request;
+    }
+}
index 73f3d89..39566ec 100644 (file)
@@ -15,11 +15,13 @@ namespace TYPO3\CMS\Backend\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerAwareTrait;
 use TYPO3\CMS\Backend\Exception;
+use TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent;
 use TYPO3\CMS\Backend\LoginProvider\LoginProviderInterface;
 use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
@@ -99,13 +101,17 @@ class LoginController implements LoggerAwareInterface
      * @var DocumentTemplate
      */
     protected $documentTemplate;
+
+    protected $eventDispatcher;
+
     /**
-     * @var \TYPO3\CMS\Core\Information\Typo3Copyright
+     * @var Typo3Copyright
      */
     private $copyright;
 
-    public function __construct(Typo3Copyright $copyright)
+    public function __construct(Typo3Copyright $copyright, EventDispatcherInterface $eventDispatcher)
     {
+        $this->eventDispatcher = $eventDispatcher;
         $this->copyright = $copyright;
     }
 
@@ -302,6 +308,15 @@ class LoginController implements LoggerAwareInterface
 
         /** @var LoginProviderInterface $loginProvider */
         $loginProvider = GeneralUtility::makeInstance($this->loginProviders[$this->loginProviderIdentifier]['provider']);
+
+        $this->eventDispatcher->dispatch(
+            new ModifyPageLayoutOnLoginProviderSelectionEvent(
+                $this,
+                $this->view,
+                $pageRenderer
+            )
+        );
+
         $loginProvider->render($this->view, $pageRenderer, $this);
 
         $content = $this->documentTemplate->startPage('TYPO3 CMS Login: ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
diff --git a/typo3/sysext/backend/Classes/LoginProvider/Event/ModifyPageLayoutOnLoginProviderSelectionEvent.php b/typo3/sysext/backend/Classes/LoginProvider/Event/ModifyPageLayoutOnLoginProviderSelectionEvent.php
new file mode 100644 (file)
index 0000000..3987f25
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+namespace TYPO3\CMS\Backend\LoginProvider\Event;
+
+/*
+ * 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\Backend\Controller\LoginController;
+use TYPO3\CMS\Core\Page\PageRenderer;
+use TYPO3\CMS\Fluid\View\StandaloneView;
+
+/**
+ * Allows to modify variables for the view depending on a special login provider set in the controller.
+ */
+final class ModifyPageLayoutOnLoginProviderSelectionEvent
+{
+    /**
+     * @var LoginController
+     */
+    private $controller;
+
+    /**
+     * @var StandaloneView
+     */
+    private $view;
+
+    /**
+     * @var PageRenderer
+     */
+    private $pageRenderer;
+
+    public function __construct(LoginController $controller, StandaloneView $view, PageRenderer $pageRenderer)
+    {
+        $this->controller = $controller;
+        $this->view = $view;
+        $this->pageRenderer = $pageRenderer;
+    }
+
+    public function getController(): LoginController
+    {
+        return $this->controller;
+    }
+
+    public function getView(): StandaloneView
+    {
+        return $this->view;
+    }
+
+    public function getPageRenderer(): PageRenderer
+    {
+        return $this->pageRenderer;
+    }
+}
index e649f2d..c965b39 100644 (file)
@@ -17,8 +17,6 @@ namespace TYPO3\CMS\Backend\LoginProvider;
 use TYPO3\CMS\Backend\Controller\LoginController;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\Object\ObjectManager;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Fluid\View\StandaloneView;
 
 /**
@@ -27,8 +25,6 @@ use TYPO3\CMS\Fluid\View\StandaloneView;
  */
 class UsernamePasswordLoginProvider implements LoginProviderInterface
 {
-    const SIGNAL_getPageRenderer = 'getPageRenderer';
-
     /**
      * @param StandaloneView $view
      * @param PageRenderer $pageRenderer
@@ -37,8 +33,6 @@ class UsernamePasswordLoginProvider implements LoginProviderInterface
      */
     public function render(StandaloneView $view, PageRenderer $pageRenderer, LoginController $loginController)
     {
-        GeneralUtility::makeInstance(ObjectManager::class)->get(Dispatcher::class)->dispatch(__CLASS__, self::SIGNAL_getPageRenderer, [$pageRenderer]);
-
         $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/UserPassLogin');
 
         $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/UserPassLoginForm.html'));
index faccb2c..62b8b46 100644 (file)
@@ -14,12 +14,14 @@ namespace TYPO3\CMS\Backend\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use Psr\Log\LoggerInterface;
 use TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher;
 use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
+use TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent;
 use TYPO3\CMS\Core\Configuration\Loader\PageTsConfigLoader;
 use TYPO3\CMS\Core\Configuration\Parser\PageTsConfigParser;
 use TYPO3\CMS\Core\Core\Environment;
@@ -762,10 +764,9 @@ class BackendUtility
             $tsDataArray['uid_' . $v['uid']] = $v['TSconfig'];
         }
 
-        $tsDataArray = static::emitGetPagesTSconfigPreIncludeSignal($tsDataArray, $id, $rootLine);
-        $tsDataArray = TypoScriptParser::checkIncludeLines_array($tsDataArray);
-
-        return $tsDataArray;
+        $eventDispatcher = GeneralUtility::getContainer()->get(EventDispatcherInterface::class);
+        $event = $eventDispatcher->dispatch(new ModifyLoadedPageTsConfigEvent($tsDataArray, $rootLine));
+        return TypoScriptParser::checkIncludeLines_array($event->getTsConfig());
     }
 
     /*******************************************
@@ -3943,37 +3944,6 @@ class BackendUtility
     }
 
     /**
-     * Get the SignalSlot dispatcher
-     *
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
-     */
-    protected static function getSignalSlotDispatcher()
-    {
-        return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
-    }
-
-    /**
-     * Emits signal to modify the page TSconfig before include
-     *
-     * @param array $TSdataArray Current TSconfig data array - Can be modified by slots!
-     * @param int $id Page ID we are handling
-     * @param array $rootLine Rootline array of page
-     * @return array Modified Data array
-     */
-    protected static function emitGetPagesTSconfigPreIncludeSignal(
-        array $TSdataArray,
-        $id,
-        array $rootLine
-    ) {
-        $signalArguments = static::getSignalSlotDispatcher()->dispatch(
-            __CLASS__,
-            'getPagesTSconfigPreInclude',
-            [$TSdataArray, $id, $rootLine, false]
-        );
-        return $signalArguments[0];
-    }
-
-    /**
      * @param string $table
      * @return Connection
      */
index b9a6491..90f55c8 100644 (file)
@@ -19,6 +19,9 @@ services:
   TYPO3\CMS\Backend\History\RecordHistoryRollback:
     public: true
 
+  TYPO3\CMS\Backend\Controller\EditDocumentController:
+    tags: ['backend.controller']
+
   TYPO3\CMS\Backend\Controller\LoginController:
     tags: ['backend.controller']
 
@@ -33,6 +36,22 @@ services:
         identifier: 'legacy-slot'
         method: 'onSystemInformationToolbarEvent'
         event: TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onLoginProviderGetPageRenderer'
+        event: TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'emitGetPagesTSconfigPreIncludeSignalBackendUtility'
+        event: TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onPreInitEditDocumentController'
+        event: TYPO3\CMS\Backend\Controller\Event\BeforeFormEnginePageInitializedEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onInitEditDocumentController'
+        event: TYPO3\CMS\Backend\Controller\Event\AfterFormEnginePageInitializedEvent
 
   # Category security checks for backend users
   TYPO3\CMS\Backend\Security\CategoryPermissionsAspect:
index 8630752..6c3bf1d 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Backend\Tests\Unit\Controller;
  */
 
 use Prophecy\Argument;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Backend\Controller\EditDocumentController;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Core\Localization\LanguageService;
@@ -52,10 +53,11 @@ class EditDocumentControllerTest extends UnitTestCase
         $GLOBALS['LANG'] = $this->prophesize(LanguageService::class)->reveal();
         GeneralUtility::addInstance(ModuleTemplate::class, $moduleTemplate->reveal());
 
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
         $mock = \Closure::bind(static function (EditDocumentController $editDocumentController) use (&$result, $typoScript) {
             return $editDocumentController->parseAdditionalGetParameters($result, $typoScript);
         }, null, EditDocumentController::class);
-        $mock(new EditDocumentController());
+        $mock(new EditDocumentController($eventDispatcher->reveal()));
 
         self::assertSame($expectedParameters, $result);
     }
index c11d1e2..0e78b11 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Backend\Tests\Unit\Utility;
 
 use Prophecy\Argument;
 use Prophecy\Prophecy\ObjectProphecy;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher;
 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\LabelFromItemListMergedReturnsCorrectFieldsFixture;
 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForGroupWithMultipleAllowedTablesFixture;
@@ -24,6 +25,8 @@ use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForSelectWithMMR
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
+use TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent;
+use TYPO3\CMS\Core\Configuration\Loader\PageTsConfigLoader;
 use TYPO3\CMS\Core\Configuration\Parser\PageTsConfigParser;
 use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
@@ -283,7 +286,7 @@ class BackendUtilityTest extends UnitTestCase
         $relationHandlerInstance = $relationHandlerProphet->reveal();
         $relationHandlerInstance->tableArray['sys_category'] = [1, 2];
 
-        list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection('sys_category');
+        [$queryBuilderProphet, $connectionPoolProphet] = $this->mockDatabaseConnection('sys_category');
         $statementProphet = $this->prophesize(\Doctrine\DBAL\Driver\Statement::class);
         $statementProphet->fetch()->shouldBeCalled()->willReturn(
             [
@@ -1035,6 +1038,10 @@ class BackendUtilityTest extends UnitTestCase
     {
         $expected = ['called.' => ['config']];
         $pageId = 13;
+        $eventDispatcherProphecy = $this->prophesize(EventDispatcherInterface::class);
+        $eventDispatcherProphecy->dispatch(Argument::any())->willReturn(new ModifyLoadedPageTsConfigEvent([], []));
+        $loader = new PageTsConfigLoader($eventDispatcherProphecy->reveal());
+        GeneralUtility::addInstance(PageTsConfigLoader::class, $loader);
         $parserProphecy = $this->prophesize(PageTsConfigParser::class);
         $parserProphecy->parse(Argument::cetera())->willReturn($expected);
         GeneralUtility::addInstance(PageTsConfigParser::class, $parserProphecy->reveal());
diff --git a/typo3/sysext/beuser/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/beuser/Classes/Compatibility/SlotReplacement.php
new file mode 100644 (file)
index 0000000..54e864e
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Beuser\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\Backend\Authentication\Event\SwitchUserEvent;
+use TYPO3\CMS\Beuser\Controller\BackendUserController;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher;
+
+/**
+ * This class provides a replacement for all existing signals in EXT:beuser 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 onSwitchUser(SwitchUserEvent $event): void
+    {
+        $this->signalSlotDispatcher->dispatch(
+            BackendUserController::class,
+            'switchUser',
+            [$event->getTargetUser()]
+        );
+    }
+}
index fc7a32e..61a4dab 100644 (file)
@@ -14,10 +14,13 @@ 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;
 use TYPO3\CMS\Core\Session\SessionManager;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\HttpUtility;
 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
@@ -59,6 +62,11 @@ class BackendUserController extends ActionController
     protected $backendUserSessionRepository;
 
     /**
+     * @var EventDispatcherInterface
+     */
+    protected $eventDispatcher;
+
+    /**
      * @param \TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService
      */
     public function injectModuleDataStorageService(\TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService)
@@ -90,6 +98,11 @@ class BackendUserController extends ActionController
         $this->backendUserSessionRepository = $backendUserSessionRepository;
     }
 
+    public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher)
+    {
+        $this->eventDispatcher = $eventDispatcher;
+    }
+
     /**
      * Load and persist module data
      *
@@ -279,10 +292,15 @@ class BackendUserController extends ActionController
                 ]
             );
 
-            $this->emitSwitchUserSignal($targetUser);
+            $event = new SwitchUserEvent(
+                $this->getBackendUserAuthentication()->getSessionId(),
+                $targetUser,
+                $this->getBackendUserAuthentication()->user
+            );
+            $this->eventDispatcher->dispatch($event);
 
             $redirectUrl = 'index.php' . ($GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] ? '' : '?commandLI=1');
-            \TYPO3\CMS\Core\Utility\HttpUtility::redirect($redirectUrl);
+            HttpUtility::redirect($redirectUrl);
         }
     }
 
@@ -314,16 +332,6 @@ class BackendUserController extends ActionController
     }
 
     /**
-     * Emit a signal when using the "switch to user" functionality
-     *
-     * @param array $targetUser
-     */
-    protected function emitSwitchUserSignal(array $targetUser)
-    {
-        $this->signalSlotDispatcher->dispatch(__CLASS__, 'switchUser', [$targetUser]);
-    }
-
-    /**
      * @return BackendUserAuthentication
      */
     protected function getBackendUserAuthentication(): BackendUserAuthentication
index 2415fd4..7e18156 100644 (file)
@@ -6,3 +6,11 @@ services:
 
   TYPO3\CMS\Beuser\:
     resource: '../Classes/*'
+
+  # Listener for old Signal Slots
+  TYPO3\CMS\Beuser\Compatibility\SlotReplacement:
+    tags:
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onSwitchUser'
+        event: TYPO3\CMS\Backend\Authentication\Event\SwitchUserEvent
diff --git a/typo3/sysext/core/Classes/Configuration/Event/ModifyLoadedPageTsConfigEvent.php b/typo3/sysext/core/Classes/Configuration/Event/ModifyLoadedPageTsConfigEvent.php
new file mode 100644 (file)
index 0000000..5989e20
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Configuration\Event;
+
+/*
+ * 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!
+ */
+
+/**
+ * Extensions can modify pageTSConfig entries that can be overridden or added, based on the root line
+ */
+final class ModifyLoadedPageTsConfigEvent
+{
+    /**
+     * @var array
+     */
+    private $tsConfig;
+
+    /**
+     * @var array
+     */
+    private $rootLine;
+
+    public function __construct(array $tsConfig, array $rootLine)
+    {
+        $this->tsConfig = $tsConfig;
+        $this->rootLine = $rootLine;
+    }
+
+    public function getTsConfig(): array
+    {
+        return $this->tsConfig;
+    }
+
+    public function addTsConfig(string $tsConfig): void
+    {
+        $this->tsConfig[] = $tsConfig;
+    }
+
+    public function setTsConfig(array $tsConfig): void
+    {
+        $this->tsConfig = $tsConfig;
+    }
+
+    public function getRootLine(): array
+    {
+        return $this->rootLine;
+    }
+}
index ee5c631..6c88536 100644 (file)
@@ -15,6 +15,8 @@ namespace TYPO3\CMS\Core\Configuration\Loader;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
+use TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent;
 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -34,6 +36,16 @@ use TYPO3\CMS\Core\Utility\PathUtility;
 class PageTsConfigLoader
 {
     /**
+     * @var EventDispatcherInterface
+     */
+    protected $eventDispatcher;
+
+    public function __construct(EventDispatcherInterface $eventDispatcher)
+    {
+        $this->eventDispatcher = $eventDispatcher;
+    }
+
+    /**
      * Main method to get all PageTSconfig from the rootline including the defaultTSconfig settings.
      * @param array $rootLine
      * @return string
@@ -87,7 +99,10 @@ class PageTsConfigLoader
             }
             $tsData['page_' . $page['uid']] = $page['TSconfig'] ?? '';
         }
+
+        $event = $this->eventDispatcher->dispatch(new ModifyLoadedPageTsConfigEvent($tsData, $rootLine));
+
         // Apply includes
-        return TypoScriptParser::checkIncludeLines_array($tsData);
+        return TypoScriptParser::checkIncludeLines_array($event->getTsConfig());
     }
 }
index dc518de..fc6ed93 100644 (file)
@@ -26,6 +26,9 @@ services:
   TYPO3\CMS\Core\Http\MiddlewareDispatcher:
     autoconfigure: false
 
+  TYPO3\CMS\Core\Configuration\Loader\PageTsConfigLoader:
+    public: true
+
   TYPO3\CMS\Core\Database\Schema\SqlReader:
     public: true
 
index a44f9dc..7b0c050 100644 (file)
@@ -10,21 +10,37 @@ Description
 ===========
 
 The following Signal Slots have been replaced by new PSR-14 events
-which are a 1:1 equivalent:
+which can be used as 1:1 equivalents:
 
-- :php:`TYPO3\CMS\Core\Imaging\IconFactory::buildIconForResourceSignal`
+- :php:`TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::getSystemInformation`
+- :php:`TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::loadMessages`
+- :php:`TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider::getPageRenderer`
+- :php:`TYPO3\CMS\Backend\Controller\EditDocumentController::preInitAfter`
+- :php:`TYPO3\CMS\Backend\Controller\EditDocumentController::initAfter`
+- :php:`TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfigPreInclude`
+- :php:`TYPO3\CMS\Beuser\Controller\BackendUserController::switchUser`
 - :php:`TYPO3\CMS\Core\Database\SoftReferenceIndex::setTypoLinkPartsElement`
 - :php:`TYPO3\CMS\Core\Database\ReferenceIndex::shouldExcludeTableFromReferenceIndex`
+- :php:`TYPO3\CMS\Core\Imaging\IconFactory::buildIconForResourceSignal`
+- :php:`TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::PostProcessTreeData`
 - :php:`TYPO3\CMS\Core\Utility\ExtensionManagementUtility::tcaIsBeingBuilt`
+- :php:`TYPO3\CMS\Impexp\Utility\ImportExportUtility::afterImportExportInitialisation`
 - :php:`TYPO3\CMS\Install\Service\SqlExpectedSchemaService::tablesDefinitionIsBeingBuilt`
-- :php:`TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::PostProcessTreeData`
-- :php:`TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::getSystemInformation`
-- :php:`TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::loadMessages`
+- :php:`TYPO3\CMS\Lang\Service\TranslationService::postProcessMirrorUrl`
+- :php:`TYPO3\CMS\Linkvalidator\LinkAnalyzer::beforeAnalyzeRecord`
+- :php:`TYPO3\CMS\Seo\Canonical\CanonicalGenerator::beforeGeneratingCanonical`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_BeforeCaching`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_PostProcesss`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GetDataArray_PostProcesss`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_SortDataArray_PostProcesss`
 
-In addition, the following public constant, marking a signal name, is deprecated:
+In addition, the following public constants, marking a signal name, are deprecated:
 
 - :php:`TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::SIGNAL_PostProcessTreeData`
-
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_BeforeCaching`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_PostProcesss`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GetDataArray_PostProcesss`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_SortDataArray_PostProcesss`
 
 Impact
 ======
@@ -42,12 +58,25 @@ Migration
 
 Use the new PSR-14 alternatives:
 
+- :php:`TYPO3\CMS\Backend\Authentication\Event\SwitchUserEvent`
+- :php:`TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent`
+- :php:`TYPO3\CMS\Backend\Controller\Event\BeforeFormEnginePageInitializedEvent`
+- :php:`TYPO3\CMS\Backend\Controller\Event\AfterFormEnginePageInitializedEvent`
+- :php:`TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent`
 - :php:`TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent`
 - :php:`TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent`
 - :php:`TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent`
 - :php:`TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent`
 - :php:`TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent`
 - :php:`TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent`
-- :php:`TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent`
+- :php:`TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent`
+- :php:`TYPO3\CMS\Impexp\Event\BeforeImportEvent`
+- :php:`TYPO3\CMS\Install\Service\Event\ModifyLanguagePackRemoteBaseUrlEvent`
+- :php:`TYPO3\CMS\Linkvalidator\Event\BeforeRecordIsAnalyzedEvent`
+- :php:`TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent`
+- :php:`TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent`
+- :php:`TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent`
+- :php:`TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent`
+- :php:`TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent`
 
 .. index:: PHP-API, FullyScanned, ext:core
index 078fd11..a193a51 100644 (file)
@@ -13,24 +13,50 @@ PSR-14 EventDispatching allows for TYPO3 Extensions or PHP packages to extend TY
 
 The following new PSR-14 events have been introduced:
 
+- :php:`TYPO3\CMS\Backend\Authentication\Event\SwitchUserEvent`
+- :php:`TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent`
+- :php:`TYPO3\CMS\Backend\Controller\Event\BeforeFormEnginePageInitializedEvent`
+- :php:`TYPO3\CMS\Backend\Controller\Event\AfterFormEnginePageInitializedEvent`
+- :php:`TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent`
 - :php:`TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent`
 - :php:`TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent`
 - :php:`TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent`
 - :php:`TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent`
 - :php:`TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent`
 - :php:`TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent`
-- :php:`TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent`
+- :php:`TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent`
+- :php:`TYPO3\CMS\Impexp\Event\BeforeImportEvent`
+- :php:`TYPO3\CMS\Install\Service\Event\ModifyLanguagePackRemoteBaseUrlEvent`
+- :php:`TYPO3\CMS\Linkvalidator\Event\BeforeRecordIsAnalyzedEvent`
+- :php:`TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent`
+- :php:`TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent`
+- :php:`TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent`
+- :php:`TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent`
+- :php:`TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent`
 
 They replace the existing Extbase-based Signal Slots
 
-- :php:`TYPO3\CMS\Core\Imaging\IconFactory::buildIconForResourceSignal`
+- :php:`TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::getSystemInformation`
+- :php:`TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::loadMessages`
+- :php:`TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider::getPageRenderer`
+- :php:`TYPO3\CMS\Backend\Controller\EditDocumentController::preInitAfter`
+- :php:`TYPO3\CMS\Backend\Controller\EditDocumentController::initAfter`
+- :php:`TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfigPreInclude`
+- :php:`TYPO3\CMS\Beuser\Controller\BackendUserController::switchUser`
 - :php:`TYPO3\CMS\Core\Database\SoftReferenceIndex::setTypoLinkPartsElement`
 - :php:`TYPO3\CMS\Core\Database\ReferenceIndex::shouldExcludeTableFromReferenceIndex`
+- :php:`TYPO3\CMS\Core\Imaging\IconFactory::buildIconForResourceSignal`
+- :php:`TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::PostProcessTreeData`
 - :php:`TYPO3\CMS\Core\Utility\ExtensionManagementUtility::tcaIsBeingBuilt`
+- :php:`TYPO3\CMS\Impexp\Utility\ImportExportUtility::afterImportExportInitialisation`
 - :php:`TYPO3\CMS\Install\Service\SqlExpectedSchemaService::tablesDefinitionIsBeingBuilt`
-- :php:`TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::PostProcessTreeData`
-- :php:`TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::getSystemInformation`
-- :php:`TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem::loadMessages`
+- :php:`TYPO3\CMS\Lang\Service\TranslationService::postProcessMirrorUrl`
+- :php:`TYPO3\CMS\Linkvalidator\LinkAnalyzer::beforeAnalyzeRecord`
+- :php:`TYPO3\CMS\Seo\Canonical\CanonicalGenerator::beforeGeneratingCanonical`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_BeforeCaching`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_PostProcesss`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GetDataArray_PostProcesss`
+- :php:`TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_SortDataArray_PostProcesss`
 
 
 Impact
index 75e0391..9083a65 100644 (file)
@@ -15,6 +15,9 @@ namespace TYPO3\CMS\Core\Tests\Unit\Configuration\Loader;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Prophecy\Argument;
+use Psr\EventDispatcher\EventDispatcherInterface;
+use TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent;
 use TYPO3\CMS\Core\Configuration\Loader\PageTsConfigLoader;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
@@ -29,7 +32,10 @@ class PageTsConfigLoaderTest extends UnitTestCase
             'default' => $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig']
         ];
         $expectedString = implode('"\n[GLOBAL]\n"', $expected);
-        $subject = new PageTsConfigLoader();
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+        $subject = new PageTsConfigLoader($eventDispatcher->reveal());
+        $event = new ModifyLoadedPageTsConfigEvent($expected, []);
+        $eventDispatcher->dispatch(Argument::type(ModifyLoadedPageTsConfigEvent::class))->willReturn($event);
         $result = $subject->collect([]);
         self::assertSame($expected, $result);
 
@@ -48,7 +54,10 @@ class PageTsConfigLoaderTest extends UnitTestCase
             'page_27' => '',
         ];
         $rootLine = [['uid' => 0, 'pid' => 0], ['uid' => 13, 'TSconfig' => 'waiting for = love'], ['uid' => 27, 'TSconfig' => '']];
-        $subject = new PageTsConfigLoader();
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+        $event = new ModifyLoadedPageTsConfigEvent($expected, $rootLine);
+        $eventDispatcher->dispatch(Argument::type(ModifyLoadedPageTsConfigEvent::class))->willReturn($event);
+        $subject = new PageTsConfigLoader($eventDispatcher->reveal());
         $result = $subject->collect($rootLine);
         self::assertSame($expected, $result);
     }
@@ -66,7 +75,10 @@ class PageTsConfigLoaderTest extends UnitTestCase
             'page_27' => '',
         ];
         $rootLine = [['uid' => 13, 'TSconfig' => 'waiting for = love', 'tsconfig_includes' => 'EXT:core/Tests/Unit/Configuration/Loader/Fixtures/included.typoscript'], ['uid' => 27, 'TSconfig' => '']];
-        $subject = new PageTsConfigLoader();
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+        $event = new ModifyLoadedPageTsConfigEvent($expected, $rootLine);
+        $eventDispatcher->dispatch(Argument::type(ModifyLoadedPageTsConfigEvent::class))->willReturn($event);
+        $subject = new PageTsConfigLoader($eventDispatcher->reveal());
         $result = $subject->collect($rootLine);
         self::assertSame($expected, $result);
     }
@@ -83,7 +95,10 @@ class PageTsConfigLoaderTest extends UnitTestCase
         ];
         $expectedString = implode("\n[GLOBAL]\n", $expected);
         $rootLine = [['uid' => 13, 'TSconfig' => 'waiting for = love', 'tsconfig_includes' => 'EXT:core/Tests/Unit/Configuration/Loader/Fixtures/me_does_not_exist.typoscript'], ['uid' => 27, 'TSconfig' => '']];
-        $subject = new PageTsConfigLoader();
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+        $event = new ModifyLoadedPageTsConfigEvent($expected, $rootLine);
+        $eventDispatcher->dispatch(Argument::type(ModifyLoadedPageTsConfigEvent::class))->willReturn($event);
+        $subject = new PageTsConfigLoader($eventDispatcher->reveal());
         $result = $subject->collect($rootLine);
         self::assertSame($expected, $result);
 
index 1d239c5..287347e 100644 (file)
@@ -17,9 +17,18 @@ namespace TYPO3\CMS\Extbase\SignalSlot;
  */
 
 use Psr\Log\LoggerInterface;
+use TYPO3\CMS\Backend\Authentication\Event\SwitchUserEvent;
 use TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent;
 use TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem;
+use TYPO3\CMS\Backend\Controller\EditDocumentController;
+use TYPO3\CMS\Backend\Controller\Event\AfterFormEnginePageInitializedEvent;
+use TYPO3\CMS\Backend\Controller\Event\BeforeFormEnginePageInitializedEvent;
+use TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent;
+use TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Beuser\Controller\BackendUserController;
 use TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent;
+use TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent;
 use TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent;
 use TYPO3\CMS\Core\Database\ReferenceIndex;
 use TYPO3\CMS\Core\Database\SoftReferenceIndex;
@@ -78,6 +87,18 @@ use TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent;
 use TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
+use TYPO3\CMS\Impexp\Event\BeforeImportEvent;
+use TYPO3\CMS\Impexp\Utility\ImportExportUtility;
+use TYPO3\CMS\Install\Service\Event\ModifyLanguagePackRemoteBaseUrlEvent;
+use TYPO3\CMS\Linkvalidator\Event\BeforeRecordIsAnalyzedEvent;
+use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
+use TYPO3\CMS\Seo\Canonical\CanonicalGenerator;
+use TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent;
+use TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent;
+use TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent;
+use TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent;
+use TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent;
+use TYPO3\CMS\Workspaces\Service\GridDataService;
 
 /**
  * A dispatcher which dispatches signals by calling its registered slot methods
@@ -174,9 +195,40 @@ class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface
         DatabaseTreeDataProvider::class => [
             'PostProcessTreeData' => ModifyTreeDataEvent::class,
         ],
+        BackendUserController::class => [
+            'switchUser' => SwitchUserEvent::class
+        ],
+        BackendUtility::class => [
+            'getPagesTSconfigPreInclude' => ModifyLoadedPageTsConfigEvent::class
+        ],
+        EditDocumentController::class => [
+            'preInitAfter' => BeforeFormEnginePageInitializedEvent::class,
+            'initAfter' => AfterFormEnginePageInitializedEvent::class,
+        ],
         SystemInformationToolbarItem::class => [
             'getSystemInformation' => SystemInformationToolbarCollectorEvent::class,
             'loadMessages' => SystemInformationToolbarCollectorEvent::class
+        ],
+        UsernamePasswordLoginProvider::class => [
+            'getPageRenderer' => ModifyPageLayoutOnLoginProviderSelectionEvent::class
+        ],
+        'TYPO3\\CMS\\Lang\\Service\\TranslationService' => [
+            'postProcessMirrorUrl' => ModifyLanguagePackRemoteBaseUrlEvent::class
+        ],
+        LinkAnalyzer::class => [
+            'beforeAnalyzeRecord' => BeforeRecordIsAnalyzedEvent::class
+        ],
+        ImportExportUtility::class => [
+            'afterImportExportInitialisation' => BeforeImportEvent::class
+        ],
+        CanonicalGenerator::class => [
+            'beforeGeneratingCanonical' => ModifyUrlForCanonicalTagEvent::class
+        ],
+        GridDataService::class => [
+            GridDataService::SIGNAL_GenerateDataArray_BeforeCaching => AfterCompiledCacheableDataForWorkspaceEvent::class,
+            GridDataService::SIGNAL_GenerateDataArray_PostProcesss => AfterDataGeneratedForWorkspaceEvent::class,
+            GridDataService::SIGNAL_GetDataArray_PostProcesss => GetVersionedDataEvent::class,
+            GridDataService::SIGNAL_SortDataArray_PostProcesss => SortVersionedDataEvent::class,
         ]
     ];
 
diff --git a/typo3/sysext/impexp/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/impexp/Classes/Compatibility/SlotReplacement.php
new file mode 100644 (file)
index 0000000..04d9c80
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Impexp\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\SignalSlot\Dispatcher as SignalSlotDispatcher;
+use TYPO3\CMS\Impexp\Event\BeforeImportEvent;
+use TYPO3\CMS\Impexp\Utility\ImportExportUtility;
+
+/**
+ * This class provides a replacement for all existing signals in EXT:impexp 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 emitAfterImportExportInitialisationSignal(BeforeImportEvent $event): void
+    {
+        $this->signalSlotDispatcher->dispatch(
+            ImportExportUtility::class,
+            'afterImportExportInitialisation',
+            [$event->getImport()]
+        );
+    }
+}
diff --git a/typo3/sysext/impexp/Classes/Event/BeforeImportEvent.php b/typo3/sysext/impexp/Classes/Event/BeforeImportEvent.php
new file mode 100644 (file)
index 0000000..608fd99
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Impexp\Event;
+
+/*
+ * 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\Impexp\Import;
+
+/**
+ * This event is triggered when an import file is about to be imported
+ */
+final class BeforeImportEvent
+{
+    /**
+     * @var Import
+     */
+    private $import;
+
+    public function __construct(Import $import)
+    {
+        $this->import = $import;
+    }
+
+    public function getImport(): Import
+    {
+        return $this->import;
+    }
+}
index 485e41b..864a2c6 100644 (file)
@@ -14,9 +14,10 @@ namespace TYPO3\CMS\Impexp\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Log\LogManager;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
+use TYPO3\CMS\Impexp\Event\BeforeImportEvent;
 use TYPO3\CMS\Impexp\Import;
 
 /**
@@ -32,6 +33,16 @@ class ImportExportUtility
     protected $import;
 
     /**
+     * @var EventDispatcherInterface
+     */
+    protected $eventDispatcher;
+
+    public function __construct(EventDispatcherInterface $eventDispatcher)
+    {
+        $this->eventDispatcher = $eventDispatcher;
+    }
+
+    /**
      * @return Import|null
      */
     public function getImport(): ?Import
@@ -59,7 +70,7 @@ class ImportExportUtility
         $this->import = GeneralUtility::makeInstance(Import::class);
         $this->import->init();
 
-        $this->emitAfterImportExportInitialisationSignal($this->import);
+        $this->eventDispatcher->dispatch(new BeforeImportEvent($this->import));
 
         $importResponse = 0;
         if ($file && @is_file($file)) {
@@ -84,26 +95,4 @@ class ImportExportUtility
         }
         return $importResponse;
     }
-
-    /**
-     * Get the SignalSlot dispatcher
-     *
-     * @return Dispatcher
-     */
-    protected function getSignalSlotDispatcher()
-    {
-        return GeneralUtility::makeInstance(Dispatcher::class);
-    }
-
-    /**
-     * Emits a signal after initialization
-     *
-     * @param Import $import
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
-     */
-    protected function emitAfterImportExportInitialisationSignal(Import $import)
-    {
-        $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'afterImportExportInitialisation', [$import]);
-    }
 }
index 825fd78..4099126 100644 (file)
@@ -6,3 +6,14 @@ services:
 
   TYPO3\CMS\Impexp\:
     resource: '../Classes/*'
+
+  TYPO3\CMS\Impexp\Utility\ImportExportUtility:
+    public: true
+
+  # Listener for old Signal Slots
+  TYPO3\CMS\Impexp\Compatibility\SlotReplacement:
+    tags:
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'emitAfterImportExportInitialisationSignal'
+        event: TYPO3\CMS\Impexp\Event\BeforeImportEvent
diff --git a/typo3/sysext/install/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/install/Classes/Compatibility/SlotReplacement.php
new file mode 100644 (file)
index 0000000..03c2160
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Install\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\Core\Http\Uri;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher;
+use TYPO3\CMS\Install\Service\Event\ModifyLanguagePackRemoteBaseUrlEvent;
+
+/**
+ * This class provides a replacement for all existing signals in EXT:install 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 onLanguagePackProcessMirrorUrl(ModifyLanguagePackRemoteBaseUrlEvent $event): void
+    {
+        $languagePackBaseUrl = (string)$event->getBaseUrl();
+        $this->signalSlotDispatcher->dispatch(
+            'TYPO3\\CMS\\Lang\\Service\\TranslationService',
+            'postProcessMirrorUrl',
+            [
+                'extensionKey' => $event->getPackageKey(),
+                'mirrorUrl' => &$languagePackBaseUrl,
+            ]
+        );
+        $event->setBaseUrl(new Uri($languagePackBaseUrl));
+    }
+}
diff --git a/typo3/sysext/install/Classes/Service/Event/ModifyLanguagePackRemoteBaseUrlEvent.php b/typo3/sysext/install/Classes/Service/Event/ModifyLanguagePackRemoteBaseUrlEvent.php
new file mode 100644 (file)
index 0000000..64e3dd8
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Install\Service\Event;
+
+/*
+ * 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 Psr\Http\Message\UriInterface;
+
+/**
+ * Event to modify the main URL of a language
+ */
+final class ModifyLanguagePackRemoteBaseUrlEvent
+{
+    /**
+     * @var UriInterface
+     */
+    private $baseUrl;
+
+    /**
+     * @var string
+     */
+    private $packageKey;
+
+    public function __construct(UriInterface $baseUrl, string $packageKey)
+    {
+        $this->baseUrl = $baseUrl;
+        $this->packageKey = $packageKey;
+    }
+
+    public function getBaseUrl(): UriInterface
+    {
+        return $this->baseUrl;
+    }
+
+    public function setBaseUrl(UriInterface $baseUrl): void
+    {
+        $this->baseUrl = $baseUrl;
+    }
+
+    public function getPackageKey(): string
+    {
+        return $this->packageKey;
+    }
+}
index 480411a..89c73fc 100644 (file)
@@ -15,16 +15,17 @@ namespace TYPO3\CMS\Install\Service;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\Finder\Finder;
 use TYPO3\CMS\Core\Configuration\Features;
 use TYPO3\CMS\Core\Core\Environment;
+use TYPO3\CMS\Core\Http\Uri;
 use TYPO3\CMS\Core\Localization\Locales;
 use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\CMS\Core\Registry;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 
 /**
  * Service class handling language pack details
@@ -44,11 +45,17 @@ class LanguagePackService
      */
     protected $registry;
 
+    /**
+     * @var EventDispatcherInterface
+     */
+    protected $eventDispatcher;
+
     private const DEFAULT_LANGUAGE_PACK_URL = 'https://typo3.org/fileadmin/ter/';
     private const BETA_LANGUAGE_PACK_URL = 'https://beta-translation.typo3.org/fileadmin/ter/';
 
-    public function __construct()
+    public function __construct(EventDispatcherInterface $eventDispatcher)
     {
+        $this->eventDispatcher = $eventDispatcher ?? GeneralUtility::getContainer()->get(EventDispatcherInterface::class);
         $this->locales = GeneralUtility::makeInstance(Locales::class);
         $this->registry = GeneralUtility::makeInstance(Registry::class);
     }
@@ -232,17 +239,9 @@ class LanguagePackService
             $languagePackBaseUrl = self::BETA_LANGUAGE_PACK_URL;
         }
 
-        // Allow to modify the base url on the fly by calling a signal
-        $signalSlotDispatcher = GeneralUtility::makeInstance(Dispatcher::class);
-        $signalSlotDispatcher->dispatch(
-            'TYPO3\\CMS\\Lang\\Service\\TranslationService',
-            'postProcessMirrorUrl',
-            [
-                'extensionKey' => $key,
-                'mirrorUrl' => &$languagePackBaseUrl,
-            ]
-        );
-
+        // Allow to modify the base url on the fly
+        $event = $this->eventDispatcher->dispatch(new Event\ModifyLanguagePackRemoteBaseUrlEvent(new Uri($languagePackBaseUrl), $key));
+        $languagePackBaseUrl = $event->getBaseUrl();
         $path = ExtensionManagementUtility::extPath($key);
         $majorVersion = explode('.', TYPO3_branch)[0];
         if (strpos($path, '/sysext/') !== false) {
index c3b01d1..887b068 100644 (file)
@@ -357,5 +357,29 @@ return [
             'Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst',
             'Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst',
         ],
+    ],
+    'TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_BeforeCaching' => [
+        'restFiles' => [
+            'Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst',
+            'Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst',
+        ],
+    ],
+    'TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GenerateDataArray_PostProcesss' => [
+        'restFiles' => [
+            'Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst',
+            'Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst',
+        ],
+    ],
+    'TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_GetDataArray_PostProcesss' => [
+        'restFiles' => [
+            'Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst',
+            'Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst',
+        ],
+    ],
+    'TYPO3\CMS\Workspaces\Service\GridDataService::SIGNAL_SortDataArray_PostProcesss' => [
+        'restFiles' => [
+            'Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst',
+            'Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst',
+        ],
     ]
 ];
index 15f7634..001682a 100644 (file)
@@ -8,3 +8,12 @@ services:
         identifier: 'install/show-latest-errors'
         method: 'appendMessage'
         event: TYPO3\CMS\Backend\Backend\Event\SystemInformationToolbarCollectorEvent
+  TYPO3\CMS\Install\Compatibility\SlotReplacement:
+    autowire: true
+    autoconfigure: true
+    public: false
+    tags:
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onLanguagePackProcessMirrorUrl'
+        event: TYPO3\CMS\Install\Service\Event\ModifyLanguagePackRemoteBaseUrlEvent
diff --git a/typo3/sysext/linkvalidator/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/linkvalidator/Classes/Compatibility/SlotReplacement.php
new file mode 100644 (file)
index 0000000..9bf46d9
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Linkvalidator\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\SignalSlot\Dispatcher as SignalSlotDispatcher;
+use TYPO3\CMS\Linkvalidator\Event\BeforeRecordIsAnalyzedEvent;
+use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
+
+/**
+ * This class provides a replacement for all existing signals in EXT:linkvalidator 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 beforeLinkAnalyzerRecordIsAnalyzed(BeforeRecordIsAnalyzedEvent $event): void
+    {
+        [$results, $record] = $this->signalSlotDispatcher->dispatch(
+            LinkAnalyzer::class,
+            'beforeAnalyzeRecord',
+            [
+                $event->getResults(),
+                $event->getRecord(),
+                $event->getTableName(),
+                $event->getFields(),
+                $event->getLinkAnalyzer()
+            ]
+        );
+        $event->setRecord($record);
+        $event->setResults($results);
+    }
+}
diff --git a/typo3/sysext/linkvalidator/Classes/Event/BeforeRecordIsAnalyzedEvent.php b/typo3/sysext/linkvalidator/Classes/Event/BeforeRecordIsAnalyzedEvent.php
new file mode 100644 (file)
index 0000000..52ce744
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Linkvalidator\Event;
+
+/*
+ * 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\Linkvalidator\LinkAnalyzer;
+
+/**
+ * Event that is fired to modify results (= add results) or modify the record before the linkanalyzer analyzes
+ * the record.
+ */
+final class BeforeRecordIsAnalyzedEvent
+{
+    /**
+     * @var string
+     */
+    private $tableName;
+
+    /**
+     * @var array
+     */
+    private $record;
+
+    /**
+     * @var array
+     */
+    private $fields;
+
+    /**
+     * @var array
+     */
+    private $results;
+
+    /**
+     * @var LinkAnalyzer
+     */
+    private $linkAnalyzer;
+
+    public function __construct(string $tableName, array $record, array $fields, LinkAnalyzer $linkAnalyzer, array $results)
+    {
+        $this->tableName = $tableName;
+        $this->record = $record;
+        $this->fields = $fields;
+        $this->linkAnalyzer = $linkAnalyzer;
+        $this->results = $results;
+    }
+
+    public function getTableName(): string
+    {
+        return $this->tableName;
+    }
+
+    public function getRecord(): array
+    {
+        return $this->record;
+    }
+
+    public function setRecord(array $record): void
+    {
+        $this->record = $record;
+    }
+
+    public function getFields(): array
+    {
+        return $this->fields;
+    }
+
+    public function getResults(): array
+    {
+        return $this->results;
+    }
+
+    public function setResults(array $results): void
+    {
+        $this->results = $results;
+    }
+
+    public function getLinkAnalyzer(): LinkAnalyzer
+    {
+        return $this->linkAnalyzer;
+    }
+}
index c7a8006..21da1eb 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Linkvalidator;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
@@ -94,10 +95,13 @@ class LinkAnalyzer
     protected $tsConfig = [];
 
     /**
-     * Fill hookObjectsArr with different link types and possible XClasses.
+     * @var EventDispatcherInterface
      */
-    public function __construct()
+    protected $eventDispatcher;
+
+    public function __construct(EventDispatcherInterface $eventDispatcher)
     {
+        $this->eventDispatcher = $eventDispatcher;
         $this->getLanguageService()->includeLLFile('EXT:linkvalidator/Resources/Private/Language/Module/locallang.xlf');
     }
 
@@ -268,7 +272,10 @@ class LinkAnalyzer
      */
     public function analyzeRecord(array &$results, $table, array $fields, array $record)
     {
-        list($results, $record) = $this->emitBeforeAnalyzeRecordSignal($results, $record, $table, $fields);
+        $event = new Event\BeforeRecordIsAnalyzedEvent($table, $record, $fields, $this, $results);
+        $this->eventDispatcher->dispatch($event);
+        $results = $event->getResults();
+        $record = $event->getRecord();
 
         // Put together content of all relevant fields
         $haystack = '';
@@ -573,40 +580,6 @@ class LinkAnalyzer
     }
 
     /**
-     * Emits a signal before the record is analyzed
-     *
-     * @param array $results Array of broken links
-     * @param array $record Record to analyze
-     * @param string $table Table name of the record
-     * @param array $fields Array of fields to analyze
-     * @return array
-     */
-    protected function emitBeforeAnalyzeRecordSignal($results, $record, $table, $fields)
-    {
-        return $this->getSignalSlotDispatcher()->dispatch(
-            self::class,
-            'beforeAnalyzeRecord',
-            [$results, $record, $table, $fields, $this]
-        );
-    }
-
-    /**
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
-     */
-    protected function getSignalSlotDispatcher()
-    {
-        return $this->getObjectManager()->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
-    }
-
-    /**
-     * @return \TYPO3\CMS\Extbase\Object\ObjectManager
-     */
-    protected function getObjectManager()
-    {
-        return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
-    }
-
-    /**
      * @return LanguageService
      */
     protected function getLanguageService()
index 90fb8b5..ac4cecd 100644 (file)
@@ -24,3 +24,10 @@ services:
         identifier: 'rte-check-link-to-file'
         event: TYPO3\CMS\Core\Html\Event\BrokenLinkAnalysisEvent
         method: 'checkFileLink'
+
+  TYPO3\CMS\Linkvalidator\Compatibility\SlotReplacement:
+    tags:
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'beforeLinkAnalyzerRecordIsAnalyzed'
+        event: TYPO3\CMS\Linkvalidator\Event\BeforeRecordIsAnalyzedEvent
index e3cd3ca..032842d 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Linkvalidator\Tests\Functional;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Core\Bootstrap;
 use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
@@ -34,7 +35,6 @@ class LinkAnalyzerTest extends FunctionalTestCase
     protected function setUp(): void
     {
         parent::setUp();
-
         Bootstrap::initializeLanguageObject();
     }
 
@@ -110,7 +110,7 @@ class LinkAnalyzerTest extends FunctionalTestCase
 
         $this->importDataSet($inputFile);
 
-        $linkAnalyzer = new LinkAnalyzer();
+        $linkAnalyzer = new LinkAnalyzer($this->prophesize(EventDispatcherInterface::class)->reveal());
         $linkAnalyzer->init($searchFields, $pidList, $tsConfig);
         $linkAnalyzer->getLinkStatistics($config);
 
@@ -172,7 +172,7 @@ class LinkAnalyzerTest extends FunctionalTestCase
 
         $this->importDataSet($inputFile);
 
-        $linkAnalyzer = new LinkAnalyzer();
+        $linkAnalyzer = new LinkAnalyzer($this->prophesize(EventDispatcherInterface::class)->reveal());
         $linkAnalyzer->init($searchFields, $pidList, $tsConfig);
         $linkAnalyzer->getLinkStatistics($config);
 
@@ -234,7 +234,7 @@ class LinkAnalyzerTest extends FunctionalTestCase
 
         $this->importDataSet($inputFile);
 
-        $linkAnalyzer = new LinkAnalyzer();
+        $linkAnalyzer = new LinkAnalyzer($this->prophesize(EventDispatcherInterface::class)->reveal());
         $linkAnalyzer->init($searchFields, $pidList, $tsConfig);
         $linkAnalyzer->getLinkStatistics($config);
 
@@ -295,7 +295,7 @@ class LinkAnalyzerTest extends FunctionalTestCase
 
         $this->importDataSet($inputFile);
 
-        $linkAnalyzer = new LinkAnalyzer();
+        $linkAnalyzer = new LinkAnalyzer($this->prophesize(EventDispatcherInterface::class)->reveal());
         $linkAnalyzer->init($searchFields, $pidList, $tsConfig);
         $linkAnalyzer->getLinkStatistics($config);
 
index 6b5b4ca..c87a1b7 100644 (file)
@@ -16,11 +16,12 @@ namespace TYPO3\CMS\Seo\Canonical;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Domain\Repository\PageRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3\CMS\Frontend\Utility\CanonicalizationUtility;
+use TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent;
 
 /**
  * Class to add the canonical tag to the page
@@ -40,38 +41,21 @@ class CanonicalGenerator
     protected $pageRepository;
 
     /**
-     * @var Dispatcher
+     * @var EventDispatcherInterface
      */
-    protected $signalSlotDispatcher;
+    protected $eventDispatcher;
 
-    /**
-     * CanonicalGenerator constructor
-     *
-     * @param TypoScriptFrontendController $typoScriptFrontendController
-     * @param Dispatcher $signalSlotDispatcher
-     */
-    public function __construct(TypoScriptFrontendController $typoScriptFrontendController = null, Dispatcher $signalSlotDispatcher = null)
+    public function __construct(TypoScriptFrontendController $typoScriptFrontendController = null, EventDispatcherInterface $eventDispatcher = null)
     {
-        if ($typoScriptFrontendController === null) {
-            $typoScriptFrontendController = $this->getTypoScriptFrontendController();
-        }
-        if ($signalSlotDispatcher === null) {
-            $signalSlotDispatcher = GeneralUtility::makeInstance(Dispatcher::class);
-        }
-        $this->typoScriptFrontendController = $typoScriptFrontendController;
-        $this->signalSlotDispatcher = $signalSlotDispatcher;
+        $this->eventDispatcher = $eventDispatcher ?? GeneralUtility::getContainer()->get(EventDispatcherInterface::class);
+        $this->typoScriptFrontendController = $typoScriptFrontendController ?? $this->getTypoScriptFrontendController();
         $this->pageRepository = GeneralUtility::makeInstance(PageRepository::class);
     }
 
-    /**
-     * @return string
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
-     */
     public function generate(): string
     {
-        $href = '';
-        $this->signalSlotDispatcher->dispatch(self::class, 'beforeGeneratingCanonical', [&$href]);
+        $event = $this->eventDispatcher->dispatch(new ModifyUrlForCanonicalTagEvent(''));
+        $href = $event->getUrl();
 
         if (empty($href) && (int)$this->typoScriptFrontendController->page['no_index'] === 1) {
             return '';
diff --git a/typo3/sysext/seo/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/seo/Classes/Compatibility/SlotReplacement.php
new file mode 100644 (file)
index 0000000..756b45f
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Seo\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\SignalSlot\Dispatcher as SignalSlotDispatcher;
+use TYPO3\CMS\Seo\Canonical\CanonicalGenerator;
+use TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent;
+
+/**
+ * This class provides a replacement for all existing signals in EXT:seo 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 beforeGeneratingCanonical(ModifyUrlForCanonicalTagEvent $event): void
+    {
+        $href = $event->getUrl();
+        $this->signalSlotDispatcher->dispatch(
+            CanonicalGenerator::class,
+            'beforeGeneratingCanonical',
+            [&$href]
+        );
+        $event->setUrl($href);
+    }
+}
diff --git a/typo3/sysext/seo/Classes/Event/ModifyUrlForCanonicalTagEvent.php b/typo3/sysext/seo/Classes/Event/ModifyUrlForCanonicalTagEvent.php
new file mode 100644 (file)
index 0000000..4c634e4
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Seo\Event;
+
+/*
+ * 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!
+ */
+
+/**
+ * PSR-14 to alter (or empty) a canonical URL for the href="" attribute of a canonical URL.
+ */
+final class ModifyUrlForCanonicalTagEvent
+{
+    /**
+     * @var string
+     */
+    private $url;
+
+    public function __construct(string $url)
+    {
+        $this->url = $url;
+    }
+
+    public function getUrl(): string
+    {
+        return $this->url;
+    }
+
+    public function setUrl(string $url): void
+    {
+        $this->url = $url;
+    }
+}
index 484cb85..79ba406 100644 (file)
@@ -6,3 +6,10 @@ services:
 
   TYPO3\CMS\Seo\:
     resource: '../Classes/*'
+
+  TYPO3\CMS\Seo\Compatibility\SlotReplacement:
+    tags:
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'beforeGeneratingCanonical'
+        event: TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent
diff --git a/typo3/sysext/workspaces/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/workspaces/Classes/Compatibility/SlotReplacement.php
new file mode 100644 (file)
index 0000000..88be5cd
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Workspaces\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\SignalSlot\Dispatcher as SignalSlotDispatcher;
+use TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent;
+use TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent;
+use TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent;
+use TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent;
+use TYPO3\CMS\Workspaces\Service\GridDataService;
+
+/**
+ * This class provides a replacement for all existing signals in EXT:workspaces 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 onGenerateDataArrayBeforeCaching(AfterCompiledCacheableDataForWorkspaceEvent $event): void
+    {
+        [$obj, $dataArray, $versions] = $this->signalSlotDispatcher->dispatch(
+            GridDataService::class,
+            GridDataService::SIGNAL_GenerateDataArray_BeforeCaching,
+            [$event->getGridService(), $event->getData(), $event->getVersions()]
+        );
+        $event->setData($dataArray);
+        $event->setVersions($versions);
+    }
+
+    public function onGenerateDataArrayPostProcessing(AfterDataGeneratedForWorkspaceEvent $event): void
+    {
+        [$obj, $dataArray] = $this->signalSlotDispatcher->dispatch(
+            GridDataService::class,
+            GridDataService::SIGNAL_GenerateDataArray_PostProcesss,
+            [$event->getGridService(), $event->getData(), $event->getVersions()]
+        );
+        $event->setData($dataArray);
+    }
+
+    public function onGetDataPostProcessing(GetVersionedDataEvent $event): void
+    {
+        [$obj, $dataArray, $start, $limit, $dataArrayPart] = $this->signalSlotDispatcher->dispatch(
+            GridDataService::class,
+            GridDataService::SIGNAL_GetDataArray_PostProcesss,
+            [$event->getGridService(), $event->getData(), $event->getStart(), $event->getLimit(), $event->getDataArrayPart()]
+        );
+        $event->setData($dataArray);
+        $event->setDataArrayPart($dataArrayPart);
+    }
+
+    public function onSortDataPostProcessing(SortVersionedDataEvent $event): void
+    {
+        [$obj, $dataArray, $sortingColumn, $sortingDirection] = $this->signalSlotDispatcher->dispatch(
+            GridDataService::class,
+            GridDataService::SIGNAL_SortDataArray_PostProcesss,
+            [$event->getGridService(), $event->getData(), $event->getSortColumn(), $event->getSortDirection()]
+        );
+        $event->setData($dataArray);
+        $event->setSortColumn($sortingColumn);
+        $event->setSortDirection($sortingDirection);
+    }
+}
diff --git a/typo3/sysext/workspaces/Classes/Event/AfterCompiledCacheableDataForWorkspaceEvent.php b/typo3/sysext/workspaces/Classes/Event/AfterCompiledCacheableDataForWorkspaceEvent.php
new file mode 100644 (file)
index 0000000..db81d86
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Workspaces\Event;
+
+/*
+ * 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\Workspaces\Service\GridDataService;
+
+/**
+ * Used in the workspaces module to find all chacheable data of versions of a workspace.
+ */
+final class AfterCompiledCacheableDataForWorkspaceEvent
+{
+    /**
+     * @var GridDataService
+     */
+    private $gridService;
+
+    /**
+     * @var array
+     */
+    private $data;
+
+    /**
+     * @var array
+     */
+    private $versions;
+
+    public function __construct(GridDataService $gridService, array $data, array $versions)
+    {
+        $this->gridService = $gridService;
+        $this->data = $data;
+        $this->versions = $versions;
+    }
+
+    public function getGridService(): GridDataService
+    {
+        return $this->gridService;
+    }
+
+    public function getData(): array
+    {
+        return $this->data;
+    }
+
+    public function setData(array $data): void
+    {
+        $this->data = $data;
+    }
+
+    public function getVersions(): array
+    {
+        return $this->versions;
+    }
+
+    public function setVersions(array $versions): void
+    {
+        $this->versions = $versions;
+    }
+}
diff --git a/typo3/sysext/workspaces/Classes/Event/AfterDataGeneratedForWorkspaceEvent.php b/typo3/sysext/workspaces/Classes/Event/AfterDataGeneratedForWorkspaceEvent.php
new file mode 100644 (file)
index 0000000..70ba704
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Workspaces\Event;
+
+/*
+ * 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\Workspaces\Service\GridDataService;
+
+/**
+ * Used in the workspaces module to find all data of versions of a workspace.
+ */
+final class AfterDataGeneratedForWorkspaceEvent
+{
+    /**
+     * @var GridDataService
+     */
+    private $gridService;
+
+    /**
+     * @var array
+     */
+    private $data;
+
+    /**
+     * @var array
+     */
+    private $versions;
+
+    public function __construct(GridDataService $gridService, array $data, array $versions)
+    {
+        $this->gridService = $gridService;
+        $this->data = $data;
+        $this->versions = $versions;
+    }
+
+    public function getGridService(): GridDataService
+    {
+        return $this->gridService;
+    }
+
+    public function getData(): array
+    {
+        return $this->data;
+    }
+
+    public function setData(array $data): void
+    {
+        $this->data = $data;
+    }
+
+    public function getVersions(): array
+    {
+        return $this->versions;
+    }
+
+    public function setVersions(array $versions): void
+    {
+        $this->versions = $versions;
+    }
+}
diff --git a/typo3/sysext/workspaces/Classes/Event/GetVersionedDataEvent.php b/typo3/sysext/workspaces/Classes/Event/GetVersionedDataEvent.php
new file mode 100644 (file)
index 0000000..c9b5fc9
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Workspaces\Event;
+
+/*
+ * 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\Workspaces\Service\GridDataService;
+
+/**
+ * Used in the workspaces module to find all data of versions of a workspace.
+ * In comparison to AfterDataGeneratedForWorkspaceEvent, this one contains the
+ * cleaned / prepared data with an optional limit applied depending on the view.
+ */
+final class GetVersionedDataEvent
+{
+    /**
+     * @var GridDataService
+     */
+    private $gridService;
+
+    /**
+     * @var array
+     */
+    private $data;
+
+    /**
+     * @var array
+     */
+    private $dataArrayPart;
+
+    /**
+     * @var int
+     */
+    private $start;
+
+    /**
+     * @var int
+     */
+    private $limit;
+
+    public function __construct(GridDataService $gridService, array $data, int $start, int $limit, array $dataArrayPart)
+    {
+        $this->gridService = $gridService;
+        $this->data = $data;
+        $this->start = $start;
+        $this->limit = $limit;
+        $this->dataArrayPart = $dataArrayPart;
+    }
+
+    public function getGridService(): GridDataService
+    {
+        return $this->gridService;
+    }
+
+    public function getData(): array
+    {
+        return $this->data;
+    }
+
+    public function setData(array $data): void
+    {
+        $this->data = $data;
+    }
+
+    public function getDataArrayPart(): array
+    {
+        return $this->dataArrayPart;
+    }
+
+    public function setDataArrayPart(array $dataArrayPart): void
+    {
+        $this->dataArrayPart = $dataArrayPart;
+    }
+
+    public function getStart(): int
+    {
+        return $this->start;
+    }
+
+    public function getLimit(): int
+    {
+        return $this->limit;
+    }
+}
diff --git a/typo3/sysext/workspaces/Classes/Event/SortVersionedDataEvent.php b/typo3/sysext/workspaces/Classes/Event/SortVersionedDataEvent.php
new file mode 100644 (file)
index 0000000..b23dfb6
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Workspaces\Event;
+
+/*
+ * 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\Workspaces\Service\GridDataService;
+
+/**
+ * Used in the workspaces module after sorting all data for versions of a workspace.
+ */
+final class SortVersionedDataEvent
+{
+    /**
+     * @var GridDataService
+     */
+    private $gridService;
+
+    /**
+     * @var array
+     */
+    private $data;
+
+    /**
+     * @var string
+     */
+    private $sortColumn;
+
+    /**
+     * @var string
+     */
+    private $sortDirection;
+
+    public function __construct(GridDataService $gridService, array $data, string $sortColumn, string $sortDirection)
+    {
+        $this->gridService = $gridService;
+        $this->data = $data;
+        $this->sortColumn = $sortColumn;
+        $this->sortDirection = $sortDirection;
+    }
+
+    public function getGridService(): GridDataService
+    {
+        return $this->gridService;
+    }
+
+    public function getData(): array
+    {
+        return $this->data;
+    }
+
+    public function setData(array $data): void
+    {
+        $this->data = $data;
+    }
+
+    public function getSortColumn(): string
+    {
+        return $this->sortColumn;
+    }
+
+    public function setSortColumn(string $sortColumn): void
+    {
+        $this->sortColumn = $sortColumn;
+    }
+
+    public function getSortDirection(): string
+    {
+        return $this->sortDirection;
+    }
+
+    public function setSortDirection(string $sortDirection): void
+    {
+        $this->sortDirection = $sortDirection;
+    }
+}
index cf22174..ba74691 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Workspaces\Service;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerAwareTrait;
 use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider;
@@ -24,8 +25,11 @@ use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Versioning\VersionState;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Workspaces\Domain\Model\CombinedRecord;
+use TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent;
+use TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent;
+use TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent;
+use TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent;
 use TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder;
 
 /**
@@ -35,9 +39,21 @@ class GridDataService implements LoggerAwareInterface
 {
     use LoggerAwareTrait;
 
+    /**
+     * @deprecated will be removed in TYPO3 v11 in favor of PSR-14 events
+     */
     const SIGNAL_GenerateDataArray_BeforeCaching = 'generateDataArray.beforeCaching';
+    /**
+     * @deprecated will be removed in TYPO3 v11 in favor of PSR-14 events
+     */
     const SIGNAL_GenerateDataArray_PostProcesss = 'generateDataArray.postProcess';
+    /**
+     * @deprecated will be removed in TYPO3 v11 in favor of PSR-14 events
+     */
     const SIGNAL_GetDataArray_PostProcesss = 'getDataArray.postProcess';
+    /**
+     * @deprecated will be removed in TYPO3 v11 in favor of PSR-14 events
+     */
     const SIGNAL_SortDataArray_PostProcesss = 'sortDataArray.postProcess';
 
     const GridColumn_Collection = 'Workspaces_Collection';
@@ -85,6 +101,16 @@ class GridDataService implements LoggerAwareInterface
     protected $integrityService;
 
     /**
+     * @var EventDispatcherInterface
+     */
+    protected $eventDispatcher;
+
+    public function __construct(EventDispatcherInterface $eventDispatcher)
+    {
+        $this->eventDispatcher = $eventDispatcher;
+    }
+
+    /**
      * Generates grid list array from given versions.
      *
      * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
@@ -214,9 +240,12 @@ class GridDataService implements LoggerAwareInterface
                     }
                 }
             }
-            // Suggested slot method:
-            // methodName(\TYPO3\CMS\Workspaces\Service\GridDataService $gridData, array $dataArray, array $versions)
-            list($this->dataArray, $versions) = $this->emitSignal(self::SIGNAL_GenerateDataArray_BeforeCaching, $this->dataArray, $versions);
+
+            // Trigger a PSR-14 event
+            $event = new AfterCompiledCacheableDataForWorkspaceEvent($this, $this->dataArray, $versions);
+            $this->eventDispatcher->dispatch($event);
+            $this->dataArray = $event->getData();
+            $versions = $event->getVersions();
             // Enrich elements after everything has been processed:
             foreach ($this->dataArray as &$element) {
                 $identifier = $element['table'] . ':' . $element['t3ver_oid'];
@@ -227,9 +256,11 @@ class GridDataService implements LoggerAwareInterface
             }
             $this->setDataArrayIntoCache($versions, $filterTxt);
         }
-        // Suggested slot method:
-        // methodName(\TYPO3\CMS\Workspaces\Service\GridDataService $gridData, array $dataArray, array $versions)
-        list($this->dataArray) = $this->emitSignal(self::SIGNAL_GenerateDataArray_PostProcesss, $this->dataArray, $versions);
+
+        // Trigger a PSR-14 event
+        $event = new AfterDataGeneratedForWorkspaceEvent($this, $this->dataArray, $versions);
+        $this->eventDispatcher->dispatch($event);
+        $this->dataArray = $event->getData();
         $this->sortDataArray();
         $this->resolveDataArrayDependencies();
     }
@@ -277,9 +308,11 @@ class GridDataService implements LoggerAwareInterface
             }
         }
 
-        // Suggested slot method:
-        // methodName(\TYPO3\CMS\Workspaces\Service\GridDataService $gridData, array $dataArray, $start, $limit, array $dataArrayPart)
-        list($this->dataArray, $start, $limit, $dataArrayPart) = $this->emitSignal(self::SIGNAL_GetDataArray_PostProcesss, $this->dataArray, $start, $limit, $dataArrayPart);
+        // Trigger a PSR-14 event
+        $event = new GetVersionedDataEvent($this, $this->dataArray, $start, $limit, $dataArrayPart);
+        $this->eventDispatcher->dispatch($event);
+        $this->dataArray = $event->getData();
+        return $event->getDataArrayPart();
         return $dataArrayPart;
     }
 
@@ -375,9 +408,12 @@ class GridDataService implements LoggerAwareInterface
         } else {
             $this->logger->critical('Try to sort "' . $this->sort . '" in "\\TYPO3\\CMS\\Workspaces\\Service\\GridDataService::sortDataArray" but $this->dataArray is empty! This might be the bug #26422 which could not be reproduced yet.');
         }
-        // Suggested slot method:
-        // methodName(\TYPO3\CMS\Workspaces\Service\GridDataService $gridData, array $dataArray, $sortColumn, $sortDirection)
-        list($this->dataArray, $this->sort, $this->sortDir) = $this->emitSignal(self::SIGNAL_SortDataArray_PostProcesss, $this->dataArray, $this->sort, $this->sortDir);
+        // Trigger an event for extensibility
+        $event = new SortVersionedDataEvent($this, $this->dataArray, $this->sort, $this->sortDir);
+        $this->eventDispatcher->dispatch($event);
+        $this->dataArray = $event->getData();
+        $this->sort = $event->getSortColumn();
+        $this->sortDir = $event->getSortDirection();
     }
 
     /**
@@ -624,22 +660,6 @@ class GridDataService implements LoggerAwareInterface
     }
 
     /**
-     * Emits a signal to be handled by any registered slots.
-     *
-     * @param string $signalName Name of the signal
-     * @param array|mixed[] $arguments
-     * @return array
-     */
-    protected function emitSignal($signalName, ...$arguments)
-    {
-        // Arguments are always ($this, [method argument], [method argument], ...)
-        $signalArguments = $arguments;
-        array_unshift($signalArguments, $this);
-        $slotReturn = $this->getSignalSlotDispatcher()->dispatch(GridDataService::class, $signalName, $signalArguments);
-        return array_slice($slotReturn, 1);
-    }
-
-    /**
      * @return Dependency\CollectionService
      */
     protected function getDependencyCollectionService()
@@ -656,14 +676,6 @@ class GridDataService implements LoggerAwareInterface
     }
 
     /**
-     * @return Dispatcher
-     */
-    protected function getSignalSlotDispatcher()
-    {
-        return $this->getObjectManager()->get(Dispatcher::class);
-    }
-
-    /**
      * @return ObjectManager
      */
     protected function getObjectManager()
index a2a64f2..9c62f63 100644 (file)
@@ -11,3 +11,25 @@ services:
     class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
     factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache']
     arguments: ['workspaces_cache']
+
+  TYPO3\CMS\Workspaces\Service\GridDataService:
+    public: true
+
+  TYPO3\CMS\Workspaces\Compatibility\SlotReplacement:
+    tags:
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onGenerateDataArrayBeforeCaching'
+        event: TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onGenerateDataArrayPostProcessing'
+        event: TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onGetDataPostProcessing'
+        event: TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onSortDataPostProcessing'
+        event: TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent
index bb1d88c..3dfb34e 100644 (file)
@@ -112,7 +112,7 @@ class RemoteServerTest extends UnitTestCase
         $liveFileReferences = $this->getFileReferenceProphecies($fileFileReferenceList);
         $versionFileReferences = $this->getFileReferenceProphecies($versionFileReferenceList);
 
-        $subject = $this->getAccessibleMock(RemoteServer::class, ['__none']);
+        $subject = $this->getAccessibleMock(RemoteServer::class, ['__none'], [], '', false);
         $result = $subject->_call(
             'prepareFileReferenceDifferences',
             $liveFileReferences,