[FEATURE] Migrate various Signal Slots to PSR-14 events 31/62331/20
authorBenni Mack <benni@typo3.org>
Fri, 15 Nov 2019 20:08:56 +0000 (21:08 +0100)
committerDaniel Goerz <daniel.goerz@posteo.de>
Fri, 22 Nov 2019 16:18:52 +0000 (17:18 +0100)
This change migrates existing Extbase Signal Slots in EXT:core
to the new PSR-14 events, which allow to define a proper API
for each event fired.

The following new Events are in place:
- TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent
- TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent
- TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent
- TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent
- TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent
- TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent

The following signals are now deprecated:
- TYPO3\CMS\Core\Imaging\IconFactory::buildIconForResourceSignal
- TYPO3\CMS\Core\Database\SoftReferenceIndex::setTypoLinkPartsElement
- TYPO3\CMS\Core\Database\ReferenceIndex::shouldExcludeTableFromReferenceIndex
- TYPO3\CMS\Core\Utility\ExtensionManagementUtility::tcaIsBeingBuilt
- TYPO3\CMS\Install\Service\SqlExpectedSchemaService::tablesDefinitionIsBeingBuilt
- TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::PostProcessTreeData

Resolves: #89733
Releases: master
Change-Id: I0747c1de3b77a6be2870d87a054522a7df2fdb18
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62331
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Susanne Moog <look@susi.dev>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
41 files changed:
typo3/sysext/backend/Classes/Security/CategoryPermissionsAspect.php
typo3/sysext/backend/Configuration/Services.yaml
typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaSelectItemsTest.php
typo3/sysext/backend/ext_localconf.php
typo3/sysext/core/Classes/Cache/DatabaseSchemaService.php
typo3/sysext/core/Classes/Category/CategoryRegistry.php
typo3/sysext/core/Classes/Compatibility/SlotReplacement.php
typo3/sysext/core/Classes/Configuration/Event/AfterTcaCompilationEvent.php [new file with mode: 0644]
typo3/sysext/core/Classes/Core/Bootstrap.php
typo3/sysext/core/Classes/DataHandling/Event/AppendLinkHandlerElementsEvent.php [new file with mode: 0644]
typo3/sysext/core/Classes/DataHandling/Event/IsTableExcludedFromReferenceIndexEvent.php [new file with mode: 0644]
typo3/sysext/core/Classes/Database/Event/AlterTableDefinitionStatementsEvent.php [new file with mode: 0644]
typo3/sysext/core/Classes/Database/ReferenceIndex.php
typo3/sysext/core/Classes/Database/Schema/SchemaMigrator.php
typo3/sysext/core/Classes/Database/Schema/SqlReader.php
typo3/sysext/core/Classes/Database/SoftReferenceIndex.php
typo3/sysext/core/Classes/Imaging/Event/ModifyIconForResourcePropertiesEvent.php [new file with mode: 0644]
typo3/sysext/core/Classes/Imaging/IconFactory.php
typo3/sysext/core/Classes/ServiceProvider.php
typo3/sysext/core/Classes/Tree/Event/ModifyTreeDataEvent.php [new file with mode: 0644]
typo3/sysext/core/Classes/Tree/TableConfiguration/DatabaseTreeDataProvider.php
typo3/sysext/core/Classes/Tree/TableConfiguration/TreeDataProviderFactory.php
typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
typo3/sysext/core/Configuration/Services.yaml
typo3/sysext/core/Documentation/Changelog/master/Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Database/Schema/Parser/TableBuilderTest.php
typo3/sysext/core/Tests/Unit/Database/Schema/SqlReaderTest.php
typo3/sysext/core/Tests/Unit/Database/SoftReferenceIndexTest.php
typo3/sysext/core/Tests/Unit/Imaging/IconFactoryTest.php
typo3/sysext/core/Tests/Unit/Imaging/IconTest.php
typo3/sysext/core/Tests/Unit/Tree/TableConfiguration/TreeDataProviderFactoryTest.php
typo3/sysext/core/Tests/Unit/Utility/AccessibleProxies/ExtensionManagementUtilityAccessibleProxy.php
typo3/sysext/core/Tests/Unit/Utility/ExtensionManagementUtilityTest.php
typo3/sysext/core/ext_localconf.php
typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php
typo3/sysext/indexed_search/Classes/Service/DatabaseSchemaService.php
typo3/sysext/indexed_search/Configuration/Services.yaml
typo3/sysext/indexed_search/ext_localconf.php
typo3/sysext/install/Classes/Service/LateBootService.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassConstantMatcher.php

index f02c2e3..6ab00e0 100644 (file)
@@ -18,29 +18,28 @@ use TYPO3\CMS\Backend\Tree\TreeNode;
 use TYPO3\CMS\Backend\Tree\TreeNodeCollection;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider;
+use TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
- * We do not have AOP in TYPO3 for now, thus the aspect which
- * deals with tree data security is a slot which reacts on a signal
- * on data data object initialization.
+ * This event listener deals with tree data security which reacts on a PSR-14 event
+ * on data object initialization.
  *
- * The aspect define category mount points according to BE User permissions.
+ * The aspect defines category mount points according to BE User permissions.
  *
  * @internal This class is TYPO3-internal hook and is not considered part of the Public TYPO3 API.
  */
-class CategoryPermissionsAspect
+final class CategoryPermissionsAspect
 {
     /**
      * @var string
      */
-    protected $categoryTableName = 'sys_category';
+    private $categoryTableName = 'sys_category';
 
     /**
      * @var BackendUserAuthentication
      */
-    protected $backendUserAuthentication;
+    private $backendUserAuthentication;
 
     /**
      * @param BackendUserAuthentication|null $backendUserAuthentication
@@ -51,18 +50,20 @@ class CategoryPermissionsAspect
     }
 
     /**
-     * The slot for the signal in DatabaseTreeDataProvider, which only affects the TYPO3 Backend
+     * The listener for the event in DatabaseTreeDataProvider, which only affects the TYPO3 Backend
      *
-     * @param DatabaseTreeDataProvider $dataProvider
-     * @param TreeNode $treeData
+     * @param ModifyTreeDataEvent $event
      */
-    public function addUserPermissionsToCategoryTreeData(DatabaseTreeDataProvider $dataProvider, $treeData)
+    public function addUserPermissionsToCategoryTreeData(ModifyTreeDataEvent $event): void
     {
         // Only evaluate this in the backend
         if (!(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_BE)) {
             return;
         }
 
+        $dataProvider = $event->getProvider();
+        $treeData = $event->getTreeData();
+
         if (!$this->backendUserAuthentication->isAdmin() && $dataProvider->getTableName() === $this->categoryTableName) {
 
             // Get User permissions related to category
@@ -91,7 +92,7 @@ class CategoryPermissionsAspect
 
                 // Create an empty tree node collection to receive the secured nodes.
                 /** @var TreeNodeCollection $securedTreeNodeCollection */
-                $securedTreeNodeCollection = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNodeCollection::class);
+                $securedTreeNodeCollection = GeneralUtility::makeInstance(TreeNodeCollection::class);
 
                 foreach ($categoryMountPoints as $categoryMountPoint) {
                     $treeNode = $this->lookUpCategoryMountPointInTreeNodes((int)$categoryMountPoint, $treeNodeCollection);
@@ -113,14 +114,14 @@ class CategoryPermissionsAspect
      * @param TreeNodeCollection $treeNodeCollection
      * @return TreeNode|null
      */
-    protected function lookUpCategoryMountPointInTreeNodes($categoryMountPoint, TreeNodeCollection $treeNodeCollection)
+    private function lookUpCategoryMountPointInTreeNodes($categoryMountPoint, TreeNodeCollection $treeNodeCollection)
     {
         $result = null;
 
         // If any User permission, recursively traverse the tree and set tree part as mount point
         foreach ($treeNodeCollection as $treeNode) {
 
-            /** @var \TYPO3\CMS\Backend\Tree\TreeNode $treeNode */
+            /** @var TreeNode $treeNode */
             if ((int)$treeNode->getId() === $categoryMountPoint) {
                 $result = $treeNode;
                 break;
@@ -145,10 +146,10 @@ class CategoryPermissionsAspect
      * @param int $uid
      * @return array
      */
-    protected function findUidsInRootline($uid)
+    private function findUidsInRootline($uid)
     {
-        /** @var \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder */
-        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->categoryTableName);
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable($this->categoryTableName);
         $row = $queryBuilder
             ->select('parent')
             ->from($this->categoryTableName)
index e5c7ac6..c8814ce 100644 (file)
@@ -18,3 +18,12 @@ services:
 
   TYPO3\CMS\Backend\History\RecordHistoryRollback:
     public: true
+
+
+  # Category security checks for backend users
+  TYPO3\CMS\Backend\Security\CategoryPermissionsAspect:
+    tags:
+      - name: event.listener
+        identifier: 'backend-user-permissions'
+        method: 'addUserPermissionsToCategoryTreeData'
+        event: TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent
index 0eb322d..2a7e53e 100644 (file)
@@ -30,6 +30,7 @@ use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
 use TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer;
 use TYPO3\CMS\Core\Database\RelationHandler;
+use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Imaging\IconRegistry;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
@@ -68,6 +69,11 @@ class TcaSelectItemsTest extends UnitTestCase
         $cacheProphecy->get(Argument::cetera())->willReturn(false);
         $cacheProphecy->set(Argument::cetera())->willReturn(false);
         GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
+
+        $iconRegistryProphecy = $this->prophesize(IconRegistry::class);
+        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconRegistryProphecy->reveal());
+        $iconFactoryProphecy = $this->prophesize(IconFactory::class);
+        GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
     }
 
     /**
@@ -328,9 +334,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ],
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         $this->expectException(\UnexpectedValueException::class);
         $this->expectExceptionCode(1439298496);
 
@@ -374,9 +377,6 @@ class TcaSelectItemsTest extends UnitTestCase
         ];
         $GLOBALS['TCA_DESCR']['aTable']['columns']['']['description'] = 'aDescription';
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         /** @var LanguageService|ObjectProphecy $languageService */
         $languageService = $this->prophesize(LanguageService::class);
         $GLOBALS['LANG'] = $languageService->reveal();
@@ -443,9 +443,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ],
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         /** @var LanguageService|ObjectProphecy $languageService */
         $languageService = $this->prophesize(LanguageService::class);
         $GLOBALS['LANG'] = $languageService->reveal();
@@ -608,9 +605,6 @@ class TcaSelectItemsTest extends UnitTestCase
         ];
         $GLOBALS['TCA'] = $tca;
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         $result = (new TcaSelectItems)->addData($input);
 
         self::assertSame($expectedItems, $result['processedTca']['columns']['aField']['config']['items']);
@@ -675,9 +669,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ],
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         $expectedItems = [
             0 => [
                 0 => 'fooTableTitle aFlexFieldTitle dummy',
@@ -743,9 +734,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ],
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         /** @var LanguageService|ObjectProphecy $languageService */
         $languageService = $this->prophesize(LanguageService::class);
         $GLOBALS['LANG'] = $languageService->reveal();
@@ -817,9 +805,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ],
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         /** @var LanguageService|ObjectProphecy $languageService */
         $languageService = $this->prophesize(LanguageService::class);
         $GLOBALS['LANG'] = $languageService->reveal();
@@ -906,9 +891,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ],
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         /** @var LanguageService|ObjectProphecy $languageService */
         $languageService = $this->prophesize(LanguageService::class);
         $GLOBALS['LANG'] = $languageService->reveal();
@@ -1001,9 +983,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ],
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         /** @var LanguageService|ObjectProphecy $languageService */
         $languageService = $this->prophesize(LanguageService::class);
         $GLOBALS['LANG'] = $languageService->reveal();
@@ -1057,9 +1036,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ],
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         $siteFinder = $this->prophesize(SiteFinder::class);
         $siteFinder->getAllSites()->willReturn([
             new Site('test', 13, [
@@ -1128,9 +1104,6 @@ class TcaSelectItemsTest extends UnitTestCase
             ]
         ];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         $expectedItems = [
             0 => [
                 0 => 'aHeader',
@@ -1180,9 +1153,6 @@ class TcaSelectItemsTest extends UnitTestCase
 
         $GLOBALS['TBE_MODULES'] = [];
 
-        $iconFactoryProphecy = $this->prophesize(IconRegistry::class);
-        GeneralUtility::setSingletonInstance(IconRegistry::class, $iconFactoryProphecy->reveal());
-
         /** @var ModuleLoader|ObjectProphecy $moduleLoaderProphecy */
         $moduleLoaderProphecy = $this->prophesize(ModuleLoader::class);
         GeneralUtility::addInstance(ModuleLoader::class, $moduleLoaderProphecy->reveal());
index 7a8b4ce..8970608 100644 (file)
@@ -1,14 +1,6 @@
 <?php
 defined('TYPO3_MODE') or die();
 
-// sys_category tree check, which only affects Backend Users
-\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)->connect(
-    \TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::class,
-    \TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::SIGNAL_PostProcessTreeData,
-    \TYPO3\CMS\Backend\Security\CategoryPermissionsAspect::class,
-    'addUserPermissionsToCategoryTreeData'
-);
-
 $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][1435433106] = \TYPO3\CMS\Backend\Backend\ToolbarItems\ClearCacheToolbarItem::class;
 $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][1435433107] = \TYPO3\CMS\Backend\Backend\ToolbarItems\HelpToolbarItem::class;
 $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][1435433108] = \TYPO3\CMS\Backend\Backend\ToolbarItems\LiveSearchToolbarItem::class;
index 3205531..275f57f 100644 (file)
@@ -14,11 +14,24 @@ namespace TYPO3\CMS\Core\Cache;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent;
+
 /**
  * This service provides the sql schema for the caching framework
  */
-class DatabaseSchemaService
+final class DatabaseSchemaService
 {
+
+    /**
+     * An event listener to inject the required caching framework database tables to the
+     * tables definitions string
+     * @param AlterTableDefinitionStatementsEvent $event
+     */
+    public function addCachingFrameworkDatabaseSchema(AlterTableDefinitionStatementsEvent $event): void
+    {
+        $event->addSqlData($this->getCachingFrameworkRequiredDatabaseSchema());
+    }
+
     /**
      * Get schema SQL of required cache framework tables.
      *
@@ -26,7 +39,7 @@ class DatabaseSchemaService
      *
      * @return string Cache framework SQL
      */
-    public function getCachingFrameworkRequiredDatabaseSchema()
+    private function getCachingFrameworkRequiredDatabaseSchema()
     {
         // Use new to circumvent the singleton pattern of CacheManager
         $cacheManager = new CacheManager();
@@ -42,17 +55,4 @@ class DatabaseSchemaService
 
         return $tableDefinitions;
     }
-
-    /**
-     * A slot method to inject the required caching framework database tables to the
-     * tables definitions string
-     *
-     * @param array $sqlString
-     * @return array
-     */
-    public function addCachingFrameworkRequiredDatabaseSchemaForSqlExpectedSchemaService(array $sqlString)
-    {
-        $sqlString[] = $this->getCachingFrameworkRequiredDatabaseSchema();
-        return [$sqlString];
-    }
 }
index d63e646..8227936 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Core\Category;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\SingletonInterface;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
@@ -436,18 +437,16 @@ class CategoryRegistry implements SingletonInterface
     }
 
     /**
-     * A slot method to inject the required category database fields to the
+     * A event listener to inject the required category database fields to the
      * tables definition string
      *
-     * @param array $sqlString
-     * @return array
+     * @param AlterTableDefinitionStatementsEvent $event
      * @internal
      */
-    public function addCategoryDatabaseSchemaToTablesDefinition(array $sqlString)
+    public function addCategoryDatabaseSchema(AlterTableDefinitionStatementsEvent $event): void
     {
         $this->registerDefaultCategorizedTables();
-        $sqlString[] = $this->getDatabaseTableDefinitions();
-        return ['sqlString' => $sqlString];
+        $event->addSqlData($this->getDatabaseTableDefinitions());
     }
 
     /**
index a39737c..cbe095c 100644 (file)
@@ -17,6 +17,16 @@ namespace TYPO3\CMS\Core\Compatibility;
  */
 
 use Psr\EventDispatcher\EventDispatcherInterface;
+use TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent;
+use TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent;
+use TYPO3\CMS\Core\Database\ReferenceIndex;
+use TYPO3\CMS\Core\Database\Schema\Exception\UnexpectedSignalReturnValueTypeException;
+use TYPO3\CMS\Core\Database\Schema\SqlReader;
+use TYPO3\CMS\Core\Database\SoftReferenceIndex;
+use TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent;
+use TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent;
+use TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent;
+use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Resource\Event\AfterFileAddedEvent;
 use TYPO3\CMS\Core\Resource\Event\AfterFileAddedToIndexEvent;
 use TYPO3\CMS\Core\Resource\Event\AfterFileContentsSetEvent;
@@ -62,6 +72,9 @@ use TYPO3\CMS\Core\Resource\Index\MetaDataRepository;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Resource\ResourceStorage;
 use TYPO3\CMS\Core\Resource\Service\FileProcessingService;
+use TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent;
+use TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher;
 
@@ -115,7 +128,11 @@ class SlotReplacement
 
     public function onFileIndexRepositoryRecordUpdated(AfterFileUpdatedInIndexEvent $event): void
     {
-        $this->signalSlotDispatcher->dispatch(FileIndexRepository::class, 'recordUpdated', [$event->getRelevantProperties()]);
+        $this->signalSlotDispatcher->dispatch(
+            FileIndexRepository::class,
+            'recordUpdated',
+            [$event->getRelevantProperties()]
+        );
     }
 
     public function onFileIndexRepositoryRecordCreated(AfterFileAddedToIndexEvent $event): void
@@ -125,7 +142,11 @@ class SlotReplacement
 
     public function onFileIndexRepositoryRecordMarkedAsMissing(AfterFileMarkedAsMissingEvent $event): void
     {
-        $this->signalSlotDispatcher->dispatch(FileIndexRepository::class, 'recordMarkedAsMissing', [$event->getFileUid()]);
+        $this->signalSlotDispatcher->dispatch(
+            FileIndexRepository::class,
+            'recordMarkedAsMissing',
+            [$event->getFileUid()]
+        );
     }
 
     public function onFileIndexRepositoryRecordDeleted(AfterFileRemovedFromIndexEvent $event): void
@@ -166,7 +187,12 @@ class SlotReplacement
             ResourceStorage::class,
             FileProcessingService::SIGNAL_PreFileProcess,
             [
-                $service, $event->getDriver(), $event->getProcessedFile(), $event->getFile(), $event->getTaskType(), $event->getConfiguration()
+                $service,
+                $event->getDriver(),
+                $event->getProcessedFile(),
+                $event->getFile(),
+                $event->getTaskType(),
+                $event->getConfiguration()
             ]
         );
     }
@@ -182,7 +208,14 @@ class SlotReplacement
         $this->signalSlotDispatcher->dispatch(
             ResourceStorage::class,
             FileProcessingService::SIGNAL_PostFileProcess,
-            [$service, $event->getDriver(), $event->getProcessedFile(), $event->getFile(), $event->getTaskType(), $event->getConfiguration()]
+            [
+                $service,
+                $event->getDriver(),
+                $event->getProcessedFile(),
+                $event->getFile(),
+                $event->getTaskType(),
+                $event->getConfiguration()
+            ]
         );
     }
 
@@ -537,4 +570,115 @@ class SlotReplacement
         );
         $event->setPublicUrl($urlData['publicUrl']);
     }
+
+    /**
+     * ReferenceIndex and SoftReferenceIndex
+     */
+    public function onReferenceIndexShouldExcludeTableFromReferenceIndexSignal(
+        IsTableExcludedFromReferenceIndexEvent $event
+    ): void {
+        $excludeTable = $event->isTableExcluded();
+        $this->signalSlotDispatcher->dispatch(
+            ReferenceIndex::class,
+            'shouldExcludeTableFromReferenceIndex',
+            [
+                $event->getTable(),
+                &$excludeTable
+            ]
+        );
+        if ($excludeTable) {
+            $event->markAsExcluded();
+        }
+    }
+
+    public function onSoftReferenceIndexSetTypoLinkPartsElementSignal(AppendLinkHandlerElementsEvent $event): void
+    {
+        $linkHandlerFound = false;
+        $result = $this->signalSlotDispatcher->dispatch(
+            SoftReferenceIndex::class,
+            'setTypoLinkPartsElement',
+            [
+                $linkHandlerFound,
+                $event->getLinkParts(),
+                $event->getContent(),
+                $event->getElements(),
+                $event->getIdx(),
+                $event->getTokenId()
+            ]
+        );
+        if ($result[0]) {
+            $event->setLinkParts($result[1]);
+            $event->setContent($result[2]);
+            $event->addElements($result[3]);
+        }
+    }
+
+    /**
+     * Imaging-related
+     */
+    public function onIconFactoryEmitBuildIconForResourceSignal(ModifyIconForResourcePropertiesEvent $event): void
+    {
+        $result = $this->signalSlotDispatcher->dispatch(
+            IconFactory::class,
+            'buildIconForResourceSignal',
+            [
+                $event->getResource(),
+                $event->getSize(),
+                $event->getOptions(),
+                $event->getIconIdentifier(),
+                $event->getOverlayIdentifier()
+            ]
+        );
+        $event->setIconIdentifier($result[3]);
+        $event->setOverlayIdentifier($result[4]);
+    }
+
+    public function onExtensionManagementUtilityTcaIsBeingBuilt(AfterTcaCompilationEvent $event): void
+    {
+        list($tca) = $this->signalSlotDispatcher->dispatch(
+            ExtensionManagementUtility::class,
+            'tcaIsBeingBuilt',
+            [
+                $event->getTca()
+            ]
+        );
+        $event->setTca($tca);
+    }
+
+    public function onSqlReaderEmitTablesDefinitionIsBeingBuiltSignal(AlterTableDefinitionStatementsEvent $event): void
+    {
+        // Using the old class name from the install tool here to keep backwards compatibility.
+        $signalReturn = $this->signalSlotDispatcher->dispatch(
+            'TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService',
+            'tablesDefinitionIsBeingBuilt',
+            [$event->getSqlData()]
+        );
+
+        // This is important to support old associated returns
+        $signalReturn = array_values($signalReturn);
+        $sqlString = $signalReturn[0];
+        if (!is_array($sqlString)) {
+            throw new UnexpectedSignalReturnValueTypeException(
+                sprintf(
+                    'The signal %s of class %s returned a value of type %s, but array was expected.',
+                    'tablesDefinitionIsBeingBuilt',
+                    SqlReader::class,
+                    gettype($sqlString)
+                ),
+                1382351456
+            );
+        }
+        $event->setSqlData($sqlString);
+    }
+
+    public function onDatabaseTreeDataProviderEmitPostProcessTreeDataSignal(ModifyTreeDataEvent $event): void
+    {
+        if ($event->getProvider() instanceof DatabaseTreeDataProvider) {
+            $this->signalSlotDispatcher->dispatch(
+                DatabaseTreeDataProvider::class,
+                'PostProcessTreeData',
+                [$event->getProvider(), $event->getTreeData()]
+            );
+        }
+    }
 }
diff --git a/typo3/sysext/core/Classes/Configuration/Event/AfterTcaCompilationEvent.php b/typo3/sysext/core/Classes/Configuration/Event/AfterTcaCompilationEvent.php
new file mode 100644 (file)
index 0000000..6ea34fd
--- /dev/null
@@ -0,0 +1,46 @@
+<?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!
+ */
+
+/**
+ * Event after $GLOBALS['TCA'] is built to allow to further manipulate $tca.
+ *
+ * Side note: It is possible to check against the original TCA as this is stored within $GLOBALS['TCA']
+ * before this event is fired.
+ */
+final class AfterTcaCompilationEvent
+{
+    /**
+     * @var array
+     */
+    private $tca;
+
+    public function __construct(array $tca)
+    {
+        $this->tca = $tca;
+    }
+
+    public function getTca(): array
+    {
+        return $this->tca;
+    }
+
+    public function setTca(array $tca)
+    {
+        $this->tca = $tca;
+    }
+}
index c4e1f00..3b0a5cd 100644 (file)
@@ -18,6 +18,7 @@ use Composer\Autoload\ClassLoader;
 use Doctrine\Common\Annotations\AnnotationReader;
 use Doctrine\Common\Annotations\AnnotationRegistry;
 use Psr\Container\ContainerInterface;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Cache\Backend\BackendInterface;
 use TYPO3\CMS\Core\Cache\Backend\NullBackend;
 use TYPO3\CMS\Core\Cache\Backend\Typo3DatabaseBackend;
@@ -143,6 +144,7 @@ class Bootstrap
 
         IconRegistry::setCache($assetsCache);
         PageRenderer::setCache($assetsCache);
+        ExtensionManagementUtility::setEventDispatcher($container->get(EventDispatcherInterface::class));
         static::loadTypo3LoadedExtAndExtLocalconf(true, $coreCache);
         static::unsetReservedGlobalVariables();
         $bootState->done = true;
diff --git a/typo3/sysext/core/Classes/DataHandling/Event/AppendLinkHandlerElementsEvent.php b/typo3/sysext/core/Classes/DataHandling/Event/AppendLinkHandlerElementsEvent.php
new file mode 100644 (file)
index 0000000..fbb073b
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\DataHandling\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!
+ */
+
+/**
+ * Event fired so listeners can intercept add elements when checking links within the SoftRef parser
+ */
+final class AppendLinkHandlerElementsEvent
+{
+    /**
+     * @var array
+     */
+    private $linkParts;
+
+    /**
+     * @var string
+     */
+    private $content;
+
+    /**
+     * @var array
+     */
+    private $elements;
+
+    /**
+     * @var int
+     */
+    private $idx;
+
+    /**
+     * @var string
+     */
+    private $tokenId;
+
+    private $isResolved = false;
+
+    public function __construct(array $linkParts, string $content, array $elements, int $idx, string $tokenID)
+    {
+        $this->linkParts = $linkParts;
+        $this->content = $content;
+        $this->elements = $elements;
+        $this->idx = $idx;
+        $this->tokenId = $tokenID;
+    }
+
+    public function getLinkParts(): array
+    {
+        return $this->linkParts;
+    }
+
+    public function getContent(): string
+    {
+        return $this->content;
+    }
+
+    public function getElements(): array
+    {
+        return $this->elements;
+    }
+
+    public function getIdx(): int
+    {
+        return $this->idx;
+    }
+
+    public function getTokenId(): string
+    {
+        return $this->tokenId;
+    }
+
+    public function setLinkParts(array $linkParts): void
+    {
+        $this->linkParts = $linkParts;
+    }
+
+    public function setContent(string $content): void
+    {
+        $this->content = $content;
+    }
+
+    public function setElements(array $elements): void
+    {
+        $this->elements = $elements;
+    }
+
+    public function addElements(array $elements)
+    {
+        $this->elements = array_replace_recursive($this->elements, $elements);
+        $this->isResolved = true;
+    }
+
+    public function isResolved(): bool
+    {
+        return $this->isResolved;
+    }
+}
diff --git a/typo3/sysext/core/Classes/DataHandling/Event/IsTableExcludedFromReferenceIndexEvent.php b/typo3/sysext/core/Classes/DataHandling/Event/IsTableExcludedFromReferenceIndexEvent.php
new file mode 100644 (file)
index 0000000..70a9ccd
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\DataHandling\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\EventDispatcher\StoppableEventInterface;
+
+/**
+ * Event to intercept if a certain table should be excluded from the Reference Index.
+ * There is no need to add tables without a definition in $GLOBALS['TCA'] since
+ * ReferenceIndex only handles those.
+ */
+final class IsTableExcludedFromReferenceIndexEvent implements StoppableEventInterface
+{
+    /**
+     * @var string
+     */
+    private $table;
+
+    /**
+     * @var bool
+     */
+    private $isExcluded = false;
+
+    public function __construct(string $table)
+    {
+        $this->table = $table;
+    }
+
+    public function getTable(): string
+    {
+        return $this->table;
+    }
+
+    public function markAsExcluded()
+    {
+        $this->isExcluded = true;
+    }
+
+    public function isTableExcluded(): bool
+    {
+        return $this->isExcluded;
+    }
+
+    public function isPropagationStopped(): bool
+    {
+        return $this->isTableExcluded();
+    }
+}
diff --git a/typo3/sysext/core/Classes/Database/Event/AlterTableDefinitionStatementsEvent.php b/typo3/sysext/core/Classes/Database/Event/AlterTableDefinitionStatementsEvent.php
new file mode 100644 (file)
index 0000000..d24397d
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Database\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!
+ */
+
+/**
+ * Event to intercept the "CREATE TABLE" statement from all loaded extensions.
+ */
+final class AlterTableDefinitionStatementsEvent
+{
+    /**
+     * RAW Array of definitions from each file found.
+     * @var array
+     */
+    private $sqlData;
+
+    public function __construct(array $sqlData)
+    {
+        $this->sqlData = $sqlData;
+    }
+
+    public function addSqlData($data): void
+    {
+        $this->sqlData[] = $data;
+    }
+
+    public function getSqlData(): array
+    {
+        return $this->sqlData;
+    }
+
+    public function setSqlData(array $sqlData): void
+    {
+        $this->sqlData = $sqlData;
+    }
+}
index 973d83c..692e864 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Core\Database;
  */
 
 use Doctrine\DBAL\DBALException;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerAwareTrait;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
@@ -22,11 +23,11 @@ use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
 use TYPO3\CMS\Core\Database\Platform\PlatformInformation;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageRendererResolver;
 use TYPO3\CMS\Core\Registry;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 
 /**
  * Reference index processing and relation extraction
@@ -156,10 +157,16 @@ class ReferenceIndex implements LoggerAwareInterface
     protected $useRuntimeCache = false;
 
     /**
-     * Constructor
+     * @var EventDispatcherInterface
      */
-    public function __construct()
+    protected $eventDispatcher;
+
+    /**
+     * @param EventDispatcherInterface $eventDispatcher
+     */
+    public function __construct(EventDispatcherInterface $eventDispatcher = null)
     {
+        $this->eventDispatcher = $eventDispatcher ?? GeneralUtility::getContainer()->get(EventDispatcherInterface::class);
         $this->runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
     }
 
@@ -1330,13 +1337,11 @@ class ReferenceIndex implements LoggerAwareInterface
             return static::$excludedTables[$tableName];
         }
 
-        // Only exclude tables from ReferenceIndex which do not contain any relations and never did since existing references won't be deleted!
-        // There is no need to add tables without a definition in $GLOBALS['TCA] since ReferenceIndex only handles those.
-        $excludeTable = false;
-        $signalSlotDispatcher = GeneralUtility::makeInstance(Dispatcher::class);
-        $signalSlotDispatcher->dispatch(__CLASS__, 'shouldExcludeTableFromReferenceIndex', [$tableName, &$excludeTable]);
-
-        static::$excludedTables[$tableName] = $excludeTable;
+        // Only exclude tables from ReferenceIndex which do not contain any relations and never
+        // did since existing references won't be deleted!
+        $event = new IsTableExcludedFromReferenceIndexEvent($tableName);
+        $event = $this->eventDispatcher->dispatch($event);
+        static::$excludedTables[$tableName] = $event->isTableExcluded();
 
         return static::$excludedTables[$tableName];
     }
index d4a360e..2ba9bb8 100644 (file)
@@ -49,8 +49,6 @@ class SchemaMigrator
      * @throws \InvalidArgumentException
      * @throws \RuntimeException
      * @throws \TYPO3\CMS\Core\Database\Schema\Exception\UnexpectedSignalReturnValueTypeException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
      * @throws StatementException
      */
     public function getUpdateSuggestions(array $statements, bool $remove = false): array
@@ -84,8 +82,6 @@ class SchemaMigrator
      * @throws \InvalidArgumentException
      * @throws \RuntimeException
      * @throws \TYPO3\CMS\Core\Database\Schema\Exception\UnexpectedSignalReturnValueTypeException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
      * @throws StatementException
      */
     public function getSchemaDiffs(array $statements): array
@@ -116,8 +112,6 @@ class SchemaMigrator
      * @throws \Doctrine\DBAL\DBALException
      * @throws \Doctrine\DBAL\Schema\SchemaException
      * @throws \InvalidArgumentException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
      * @throws \TYPO3\CMS\Core\Database\Schema\Exception\UnexpectedSignalReturnValueTypeException
      * @throws StatementException
      * @throws \RuntimeException
@@ -165,8 +159,6 @@ class SchemaMigrator
      * @throws \InvalidArgumentException
      * @throws \RuntimeException
      * @throws \TYPO3\CMS\Core\Database\Schema\Exception\UnexpectedSignalReturnValueTypeException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
      * @throws StatementException
      */
     public function install(array $statements, bool $createOnly = false): array
@@ -244,8 +236,6 @@ class SchemaMigrator
      * @throws \RuntimeException
      * @throws \TYPO3\CMS\Core\Database\Schema\Exception\StatementException
      * @throws \TYPO3\CMS\Core\Database\Schema\Exception\UnexpectedSignalReturnValueTypeException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
      */
     public function parseCreateTableStatements(array $statements): array
     {
index c0b7298..120f962 100644 (file)
@@ -15,9 +15,9 @@ namespace TYPO3\CMS\Core\Database\Schema;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
+use TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent;
 use TYPO3\CMS\Core\Package\PackageManager;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 
 /**
  * Helper methods to handle raw SQL input and transform it into individual statements
@@ -28,9 +28,9 @@ use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 class SqlReader
 {
     /**
-     * @var Dispatcher
+     * @var EventDispatcherInterface
      */
-    protected $signalSlotDispatcher;
+    protected $eventDispatcher;
 
     /**
      * @var PackageManager
@@ -38,14 +38,14 @@ class SqlReader
     protected $packageManager;
 
     /**
-     * @param Dispatcher $signalSlotDispatcher
+     * @param EventDispatcherInterface $eventDispatcher
      * @param PackageManager $packageManager
      * @throws \InvalidArgumentException
      */
-    public function __construct(Dispatcher $signalSlotDispatcher = null, PackageManager $packageManager = null)
+    public function __construct(EventDispatcherInterface $eventDispatcher, PackageManager $packageManager)
     {
-        $this->signalSlotDispatcher = $signalSlotDispatcher ?: GeneralUtility::makeInstance(Dispatcher::class);
-        $this->packageManager = $packageManager ?? GeneralUtility::makeInstance(PackageManager::class);
+        $this->eventDispatcher = $eventDispatcher;
+        $this->packageManager = $packageManager;
     }
 
     /**
@@ -53,9 +53,6 @@ class SqlReader
      *
      * @param bool $withStatic TRUE if sql from ext_tables_static+adt.sql should be loaded, too.
      * @return string Concatenated SQL of loaded extensions ext_tables.sql
-     * @throws \TYPO3\CMS\Core\Database\Schema\Exception\UnexpectedSignalReturnValueTypeException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
      */
     public function getTablesDefinitionString(bool $withStatic = false): string
     {
@@ -72,7 +69,9 @@ class SqlReader
             }
         }
 
-        $sqlString = $this->emitTablesDefinitionIsBeingBuiltSignal($sqlString);
+        /** @var AlterTableDefinitionStatementsEvent $event */
+        $event = $this->eventDispatcher->dispatch(new AlterTableDefinitionStatementsEvent($sqlString));
+        $sqlString = $event->getSqlData();
 
         return implode(LF . LF, $sqlString);
     }
@@ -135,40 +134,4 @@ class SqlReader
     {
         return $this->getStatementArray($dumpContent, '^CREATE TABLE');
     }
-
-    /**
-     * Emits a signal to manipulate the tables definitions
-     *
-     * @param array $sqlString
-     * @return array
-     * @throws \TYPO3\CMS\Core\Database\Schema\Exception\UnexpectedSignalReturnValueTypeException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
-     */
-    protected function emitTablesDefinitionIsBeingBuiltSignal(array $sqlString): array
-    {
-        // Using the old class name from the install tool here to keep backwards compatibility.
-        $signalReturn = $this->signalSlotDispatcher->dispatch(
-            'TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService',
-            'tablesDefinitionIsBeingBuilt',
-            [$sqlString]
-        );
-
-        // This is important to support old associated returns
-        $signalReturn = array_values($signalReturn);
-        $sqlString = $signalReturn[0];
-        if (!is_array($sqlString)) {
-            throw new Exception\UnexpectedSignalReturnValueTypeException(
-                sprintf(
-                    'The signal %s of class %s returned a value of type %s, but array was expected.',
-                    'tablesDefinitionIsBeingBuilt',
-                    __CLASS__,
-                    gettype($sqlString)
-                ),
-                1382351456
-            );
-        }
-
-        return $sqlString;
-    }
 }
index 2f2c62e..7c78478 100644 (file)
@@ -14,13 +14,14 @@ namespace TYPO3\CMS\Core\Database;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
+use TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent;
 use TYPO3\CMS\Core\Html\HtmlParser;
 use TYPO3\CMS\Core\LinkHandling\Exception\UnknownLinkHandlerException;
 use TYPO3\CMS\Core\LinkHandling\LinkService;
 use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Resource\FileInterface;
 use TYPO3\CMS\Core\SingletonInterface;
-use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Frontend\Service\TypoLinkCodecService;
@@ -81,6 +82,16 @@ class SoftReferenceIndex implements SingletonInterface
     public $tokenID_basePrefix = '';
 
     /**
+     * @var EventDispatcherInterface
+     */
+    protected $eventDispatcher;
+
+    public function __construct(EventDispatcherInterface $eventDispatcher)
+    {
+        $this->eventDispatcher = $eventDispatcher;
+    }
+
+    /**
      * Main function through which all processing happens
      *
      * @param string $table Database table name
@@ -596,12 +607,14 @@ class SoftReferenceIndex implements SingletonInterface
                 $content = '{softref:' . $tokenID . '}';
                 break;
             default:
-                $linkHandlerFound = false;
-                list($linkHandlerFound, $tLP, $content, $newElements) = $this->emitSetTypoLinkPartsElement($linkHandlerFound, $tLP, $content, $elements, $idx, $tokenID);
-                // We need to merge the array, otherwise we would loose the reference.
-                ArrayUtility::mergeRecursiveWithOverrule($elements, $newElements);
+                $event = new AppendLinkHandlerElementsEvent($tLP, $content, $elements, $idx, $tokenID);
+                $this->eventDispatcher->dispatch($event);
+
+                $elements = $event->getElements();
+                $tLP = $event->getLinkParts();
+                $content = $event->getContent();
 
-                if (!$linkHandlerFound) {
+                if (!$event->isResolved()) {
                     $elements[$tokenID . ':' . $idx]['error'] = 'Couldn\'t decide typolink mode.';
                     return $content;
                 }
@@ -624,26 +637,4 @@ class SoftReferenceIndex implements SingletonInterface
     {
         return md5($this->tokenID_basePrefix . ':' . $index);
     }
-
-    /**
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
-     */
-    protected function getSignalSlotDispatcher()
-    {
-        return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
-    }
-
-    /**
-     * @param bool $linkHandlerFound
-     * @param array $tLP
-     * @param string $content
-     * @param array $elements
-     * @param int $idx
-     * @param string $tokenID
-     * @return array
-     */
-    protected function emitSetTypoLinkPartsElement($linkHandlerFound, $tLP, $content, $elements, $idx, $tokenID)
-    {
-        return $this->getSignalSlotDispatcher()->dispatch(static::class, 'setTypoLinkPartsElement', [$linkHandlerFound, $tLP, $content, $elements, $idx, $tokenID, $this]);
-    }
 }
diff --git a/typo3/sysext/core/Classes/Imaging/Event/ModifyIconForResourcePropertiesEvent.php b/typo3/sysext/core/Classes/Imaging/Event/ModifyIconForResourcePropertiesEvent.php
new file mode 100644 (file)
index 0000000..d769661
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Imaging\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\Core\Resource\ResourceInterface;
+
+/**
+ * This is an Event every time an icon for a resource (file or folder) is fetched, allowing
+ * to modify the icon or overlay in an event listener.
+ */
+final class ModifyIconForResourcePropertiesEvent
+{
+    /**
+     * @var ResourceInterface
+     */
+    private $resource;
+
+    /**
+     * @var string
+     */
+    private $size;
+
+    /**
+     * @var array
+     */
+    private $options;
+
+    /**
+     * @var string|null
+     */
+    private $iconIdentifier;
+
+    /**
+     * @var string|null
+     */
+    private $overlayIdentifier;
+
+    public function __construct(ResourceInterface $resource, string $size, array $options, ?string $iconIdentifier, ?string $overlayIdentifier)
+    {
+        $this->resource = $resource;
+        $this->size = $size;
+        $this->options = $options;
+        $this->iconIdentifier = $iconIdentifier;
+        $this->overlayIdentifier = $overlayIdentifier;
+    }
+
+    public function getResource(): ResourceInterface
+    {
+        return $this->resource;
+    }
+
+    public function getSize(): string
+    {
+        return $this->size;
+    }
+
+    public function getOptions(): array
+    {
+        return $this->options;
+    }
+
+    public function getIconIdentifier(): ?string
+    {
+        return $this->iconIdentifier;
+    }
+
+    public function setIconIdentifier(?string $iconIdentifier): void
+    {
+        $this->iconIdentifier = $iconIdentifier;
+    }
+
+    public function getOverlayIdentifier(): ?string
+    {
+        return $this->overlayIdentifier;
+    }
+
+    public function setOverlayIdentifier(?string $overlayIdentifier): void
+    {
+        $this->overlayIdentifier = $overlayIdentifier;
+    }
+}
index 8f7b5d8..a65e088 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Core\Imaging;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
+use TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent;
 use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Resource\FolderInterface;
 use TYPO3\CMS\Core\Resource\InaccessibleFolder;
@@ -21,7 +23,6 @@ use TYPO3\CMS\Core\Resource\ResourceInterface;
 use TYPO3\CMS\Core\Type\Icon\IconState;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Versioning\VersionState;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 
 /**
  * The main factory class, which acts as the entrypoint for generating an Icon object which
@@ -58,11 +59,18 @@ class IconFactory
     protected static $iconCache = [];
 
     /**
+     * @var EventDispatcherInterface
+     */
+    protected $eventDispatcher;
+
+    /**
+     * @param EventDispatcherInterface $eventDispatcher
      * @param IconRegistry $iconRegistry
      */
-    public function __construct(IconRegistry $iconRegistry = null)
+    public function __construct(EventDispatcherInterface $eventDispatcher = null, IconRegistry $iconRegistry = null)
     {
-        $this->iconRegistry = $iconRegistry ? $iconRegistry : GeneralUtility::makeInstance(IconRegistry::class);
+        $this->eventDispatcher = $eventDispatcher ?? GeneralUtility::getContainer()->get(EventDispatcherInterface::class);
+        $this->iconRegistry = $iconRegistry ?? GeneralUtility::makeInstance(IconRegistry::class);
         $this->recordStatusMapping = $GLOBALS['TYPO3_CONF_VARS']['SYS']['IconFactory']['recordStatusMapping'];
         $this->overlayPriorities = $GLOBALS['TYPO3_CONF_VARS']['SYS']['IconFactory']['overlayPriorities'];
     }
@@ -423,11 +431,16 @@ class IconFactory
             }
         }
 
-        unset($options['mount-root']);
-        unset($options['folder-open']);
-        list($iconIdentifier, $overlayIdentifier) =
-            $this->emitBuildIconForResourceSignal($resource, $size, $options, $iconIdentifier, $overlayIdentifier);
-        return $this->getIcon($iconIdentifier, $size, $overlayIdentifier);
+        $event = $this->eventDispatcher->dispatch(
+            new ModifyIconForResourcePropertiesEvent(
+                $resource,
+                $size,
+                $options,
+                $iconIdentifier,
+                $overlayIdentifier
+            )
+        );
+        return $this->getIcon($event->getIconIdentifier(), $size, $event->getOverlayIdentifier());
     }
 
     /**
@@ -456,45 +469,6 @@ class IconFactory
     }
 
     /**
-     * Emits a signal right after the identifiers are built.
-     *
-     * @param ResourceInterface $resource
-     * @param string $size
-     * @param array $options
-     * @param string $iconIdentifier
-     * @param string $overlayIdentifier
-     * @return mixed
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
-     * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
-     */
-    protected function emitBuildIconForResourceSignal(
-        ResourceInterface $resource,
-        $size,
-        array $options,
-        $iconIdentifier,
-        $overlayIdentifier
-    ) {
-        $result = $this->getSignalSlotDispatcher()->dispatch(
-            self::class,
-            'buildIconForResourceSignal',
-            [$resource, $size, $options, $iconIdentifier, $overlayIdentifier]
-        );
-        $iconIdentifier = $result[3];
-        $overlayIdentifier = $result[4];
-        return [$iconIdentifier, $overlayIdentifier];
-    }
-
-    /**
-     * Get the SignalSlot dispatcher
-     *
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
-     */
-    protected function getSignalSlotDispatcher()
-    {
-        return GeneralUtility::makeInstance(Dispatcher::class);
-    }
-
-    /**
      * clear icon cache
      */
     public function clearIconCache()
index ccea16a..df45112 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core;
  */
 
 use Psr\Container\ContainerInterface;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Package\AbstractServiceProvider;
 
 /**
@@ -43,6 +44,13 @@ class ServiceProvider extends AbstractServiceProvider
         ];
     }
 
+    public function getExtensions(): array
+    {
+        return [
+            EventDispatcherInterface::class => [ static::class, 'provideFallbackEventDispatcher' ],
+        ] + parent::getExtensions();
+    }
+
     public static function getCacheManager(ContainerInterface $container): Cache\CacheManager
     {
         if (!$container->get('boot.state')->done) {
@@ -110,4 +118,14 @@ class ServiceProvider extends AbstractServiceProvider
     {
         return [];
     }
+
+    public static function provideFallbackEventDispatcher(
+        ContainerInterface $container,
+        EventDispatcherInterface $eventDispatcher = null
+    ): EventDispatcherInterface {
+        // Provide a dummy / empty event dispatcher for the install tool when $eventDispatcher is null (that means when we run without symfony DI)
+        return $eventDispatcher ?? new EventDispatcher\EventDispatcher(
+            new EventDispatcher\ListenerProvider($container)
+        );
+    }
 }
diff --git a/typo3/sysext/core/Classes/Tree/Event/ModifyTreeDataEvent.php b/typo3/sysext/core/Classes/Tree/Event/ModifyTreeDataEvent.php
new file mode 100644 (file)
index 0000000..51d5f7e
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Tree\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\Tree\TreeNode;
+use TYPO3\CMS\Core\Tree\TableConfiguration\AbstractTableConfigurationTreeDataProvider;
+
+/**
+ * Allows to modify tree data for any database tree
+ */
+final class ModifyTreeDataEvent
+{
+
+    /**
+     * @var TreeNode
+     */
+    private $treeData;
+
+    /**
+     * @var AbstractTableConfigurationTreeDataProvider
+     */
+    private $provider;
+
+    public function __construct(TreeNode $treeData, AbstractTableConfigurationTreeDataProvider $provider)
+    {
+        $this->treeData = $treeData;
+        $this->provider = $provider;
+    }
+
+    public function getTreeData(): TreeNode
+    {
+        return $this->treeData;
+    }
+
+    public function setTreeData(TreeNode $treeData): void
+    {
+        $this->treeData = $treeData;
+    }
+
+    public function getProvider(): AbstractTableConfigurationTreeDataProvider
+    {
+        return $this->provider;
+    }
+}
index 917a681..19ebabb 100644 (file)
@@ -14,21 +14,24 @@ namespace TYPO3\CMS\Core\Tree\TableConfiguration;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\Object\ObjectManager;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 
 /**
  * TCA tree data provider
  */
 class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvider
 {
+    /**
+     * @deprecated, will be removed in TYPO3 v11.0, use the EventDispatcher instead of Signal/Slot logic
+     */
     const SIGNAL_PostProcessTreeData = 'PostProcessTreeData';
     const MODE_CHILDREN = 1;
     const MODE_PARENT = 2;
@@ -93,9 +96,14 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
     protected $generatedTSConfig = [];
 
     /**
-     * @var Dispatcher
+     * @var EventDispatcherInterface
      */
-    protected $signalSlotDispatcher;
+    protected $eventDispatcher;
+
+    public function __construct(EventDispatcherInterface $eventDispatcher)
+    {
+        $this->eventDispatcher = $eventDispatcher;
+    }
 
     /**
      * Sets the label field
@@ -293,7 +301,9 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
         }
         $this->treeData = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNode::class);
         $this->loadTreeData();
-        $this->emitPostProcessTreeDataSignal();
+        /** @var ModifyTreeDataEvent $event */
+        $event = $this->eventDispatcher->dispatch(new ModifyTreeDataEvent($this->treeData, $this));
+        $this->treeData = $event->getTreeData();
     }
 
     /**
@@ -507,41 +517,6 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
     }
 
     /**
-     * Emits the post processing tree data signal.
-     */
-    protected function emitPostProcessTreeDataSignal()
-    {
-        $this->getSignalSlotDispatcher()->dispatch(
-            self::class,
-            self::SIGNAL_PostProcessTreeData,
-            [$this, $this->treeData]
-        );
-    }
-
-    /**
-     * Get the SignalSlot dispatcher
-     *
-     * @return Dispatcher
-     */
-    protected function getSignalSlotDispatcher()
-    {
-        if (!isset($this->signalSlotDispatcher)) {
-            $this->signalSlotDispatcher = $this->getObjectManager()->get(Dispatcher::class);
-        }
-        return $this->signalSlotDispatcher;
-    }
-
-    /**
-     * Get the ObjectManager
-     *
-     * @return ObjectManager
-     */
-    protected function getObjectManager()
-    {
-        return GeneralUtility::makeInstance(ObjectManager::class);
-    }
-
-    /**
      * @return LanguageService|null
      */
     protected function getLanguageService(): ?LanguageService
index 6880724..2fe30d3 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Core\Tree\TableConfiguration;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
 /**
  * Builds a \TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider
  * object based on some TCA configuration
@@ -32,21 +34,21 @@ class TreeDataProviderFactory
      */
     public static function getDataProvider(array $tcaConfiguration, $table, $field, $currentValue)
     {
-        /** @var \TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider $dataProvider */
+        /** @var DatabaseTreeDataProvider $dataProvider */
         $dataProvider = null;
         if (!isset($tcaConfiguration['treeConfig']) || !is_array($tcaConfiguration['treeConfig'])) {
             throw new \InvalidArgumentException('TCA Tree configuration is invalid: "treeConfig" array is missing', 1288215890);
         }
 
         if (!empty($tcaConfiguration['treeConfig']['dataProvider'])) {
-            $dataProvider = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($tcaConfiguration['treeConfig']['dataProvider'], $tcaConfiguration, $table, $field, $currentValue);
+            $dataProvider = GeneralUtility::makeInstance($tcaConfiguration['treeConfig']['dataProvider'], $tcaConfiguration, $table, $field, $currentValue);
         }
         if (!isset($tcaConfiguration['internal_type'])) {
             $tcaConfiguration['internal_type'] = 'db';
         }
         if ($tcaConfiguration['internal_type'] === 'db') {
             if ($dataProvider === null) {
-                $dataProvider = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::class);
+                $dataProvider = GeneralUtility::makeInstance(DatabaseTreeDataProvider::class);
             }
             if (isset($tcaConfiguration['foreign_table'])) {
                 $tableName = $tcaConfiguration['foreign_table'];
index ebee301..864e880 100644 (file)
@@ -14,11 +14,14 @@ namespace TYPO3\CMS\Core\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\Finder\Finder;
 use TYPO3\CMS\Backend\Routing\Route;
 use TYPO3\CMS\Backend\Routing\Router;
+use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
 use TYPO3\CMS\Core\Category\CategoryRegistry;
+use TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent;
 use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Imaging\IconRegistry;
 use TYPO3\CMS\Core\Log\LogManager;
@@ -64,39 +67,37 @@ class ExtensionManagementUtility
     }
 
     /**
-     * @var \TYPO3\CMS\Core\Cache\CacheManager
+     * @var EventDispatcherInterface
      */
-    protected static $cacheManager;
+    protected static $eventDispatcher;
 
     /**
-     * Getter for the cache manager
+     * Sets the event dispatcher to be available.
      *
-     * @return \TYPO3\CMS\Core\Cache\CacheManager
+     * @param EventDispatcherInterface $eventDispatcher
+     * @internal only used for tests and the internal TYPO3 Bootstrap process
      */
-    protected static function getCacheManager()
+    public static function setEventDispatcher(EventDispatcherInterface $eventDispatcher)
     {
-        if (static::$cacheManager === null) {
-            static::$cacheManager = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class);
-        }
-        return static::$cacheManager;
+        static::$eventDispatcher = $eventDispatcher;
     }
 
     /**
-     * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+     * @var CacheManager
      */
-    protected static $signalSlotDispatcher;
+    protected static $cacheManager;
 
     /**
-     * Getter for the signal slot dispatcher
+     * Getter for the cache manager
      *
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+     * @return CacheManager
      */
-    protected static function getSignalSlotDispatcher()
+    protected static function getCacheManager()
     {
-        if (static::$signalSlotDispatcher === null) {
-            static::$signalSlotDispatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
+        if (static::$cacheManager === null) {
+            static::$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
         }
-        return static::$signalSlotDispatcher;
+        return static::$cacheManager;
     }
 
     /**************************************
@@ -1609,23 +1610,17 @@ tt_content.' . $key . $suffix . ' {
         $tcaPreparation = GeneralUtility::makeInstance(TcaPreparation::class);
         $GLOBALS['TCA'] = $tcaPreparation->prepare($GLOBALS['TCA']);
 
-        static::emitTcaIsBeingBuiltSignal($GLOBALS['TCA']);
+        static::dispatchTcaIsBeingBuiltEvent($GLOBALS['TCA']);
     }
 
     /**
-     * Emits the signal and uses the result of slots for the final TCA
-     * This means, that *all* slots *must* return the complete TCA to
-     * be effective. If a slot calls methods that manipulate the global array,
-     * it needs to return the global array in the end. To be future proof,
-     * a slot should manipulate the signal argument only and return it
-     * after manipulation.
+     * Triggers an event for manipulating the final TCA
      *
      * @param array $tca
      */
-    protected static function emitTcaIsBeingBuiltSignal(array $tca)
+    protected static function dispatchTcaIsBeingBuiltEvent(array $tca)
     {
-        list($tca) = static::getSignalSlotDispatcher()->dispatch(__CLASS__, 'tcaIsBeingBuilt', [$tca]);
-        $GLOBALS['TCA'] = $tca;
+        $GLOBALS['TCA'] = static::$eventDispatcher->dispatch(new AfterTcaCompilationEvent($tca))->getTca();
     }
 
     /**
index 9f2ee9b..dc518de 100644 (file)
@@ -32,6 +32,10 @@ services:
   TYPO3\CMS\Core\Html\RteHtmlParser:
     public: true
 
+  TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider:
+    shared: false
+    public: true
+
   # EventListeners
   TYPO3\CMS\Core\Compatibility\Slot\PostInitializeMailer:
     tags:
@@ -201,6 +205,30 @@ services:
         identifier: 'legacy-slot'
         method: 'onResourceStorageEmitSanitizeFileNameSignal'
         event: TYPO3\CMS\Core\Resource\Event\SanitizeFileNameEvent
+      - name: event.listener,
+        identifier: 'legacy-slot'
+        method: 'onReferenceIndexShouldExcludeTableFromReferenceIndexSignal'
+        event: TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onSoftReferenceIndexSetTypoLinkPartsElementSignal'
+        event: TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onIconFactoryEmitBuildIconForResourceSignal'
+        event: TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onExtensionManagementUtilityTcaIsBeingBuilt'
+        event: TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onSqlReaderEmitTablesDefinitionIsBeingBuiltSignal'
+        event: TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent
+      - name: event.listener
+        identifier: 'legacy-slot'
+        method: 'onDatabaseTreeDataProviderEmitPostProcessTreeDataSignal'
+        event: TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent
 
   # FAL security checks for backend users
   TYPO3\CMS\Core\Resource\Security\StoragePermissionsAspect:
@@ -217,6 +245,20 @@ services:
         method: 'processFile'
         event: TYPO3\CMS\Core\Resource\Event\BeforeFileProcessingEvent
 
+  TYPO3\CMS\Core\Cache\DatabaseSchemaService:
+    tags:
+      - name: event.listener
+        identifier: 'caching-framework'
+        method: 'addCachingFrameworkDatabaseSchema'
+        event: TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent
+
+  TYPO3\CMS\Core\Category\CategoryRegistry:
+    tags:
+      - name: event.listener
+        identifier: 'category-registry'
+        method: 'addCategoryDatabaseSchema'
+        event: TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent
+
   # clean up files
   TYPO3\CMS\Core\Resource\Processing\FileDeletionAspect:
     tags:
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst
new file mode 100644 (file)
index 0000000..2ec0058
--- /dev/null
@@ -0,0 +1,50 @@
+.. include:: ../../Includes.txt
+
+==============================================================================
+Deprecation: #89733 - Signal Slots in Core Extension migrated to PSR-14 events
+==============================================================================
+
+See :issue:`89733`
+
+Description
+===========
+
+The following Signal Slots have been replaced by new PSR-14 events
+which are a 1:1 equivalent:
+
+- :php:`TYPO3\CMS\Core\Imaging\IconFactory::buildIconForResourceSignal`
+- :php:`TYPO3\CMS\Core\Database\SoftReferenceIndex::setTypoLinkPartsElement`
+- :php:`TYPO3\CMS\Core\Database\ReferenceIndex::shouldExcludeTableFromReferenceIndex`
+- :php:`TYPO3\CMS\Core\Utility\ExtensionManagementUtility::tcaIsBeingBuilt`
+- :php:`TYPO3\CMS\Install\Service\SqlExpectedSchemaService::tablesDefinitionIsBeingBuilt`
+- :php:`\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::PostProcessTreeData`
+
+In addition, the following public constant, marking a signal name, is deprecated:
+
+- :php:`\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::SIGNAL_PostProcessTreeData`
+
+
+Impact
+======
+
+Using the mentioned signals will trigger a deprecation warning.
+
+
+Affected Installations
+======================
+
+TYPO3 installations with custom extensions using these signals.
+
+Migration
+=========
+
+Use the new PSR-14 alternatives:
+
+- :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`
+
+.. index:: PHP-API, FullyScanned, ext:core
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst
new file mode 100644 (file)
index 0000000..7529492
--- /dev/null
@@ -0,0 +1,42 @@
+.. include:: ../../Includes.txt
+
+===============================================================================
+Feature: #89733 - New PSR-14 events for existing Signal Slots in Core Extension
+===============================================================================
+
+See :issue:`89733`
+
+Description
+===========
+
+PSR-14 EventDispatching allows for TYPO3 Extensions or PHP packages to extend TYPO3 Core functionality in an exchangeable way.
+
+The following new PSR-14 events have been introduced:
+
+- :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`
+
+They replace the existing Extbase-based Signal Slots
+
+- :php:`TYPO3\CMS\Core\Imaging\IconFactory::buildIconForResourceSignal`
+- :php:`TYPO3\CMS\Core\Database\SoftReferenceIndex::setTypoLinkPartsElement`
+- :php:`TYPO3\CMS\Core\Database\ReferenceIndex::shouldExcludeTableFromReferenceIndex`
+- :php:`TYPO3\CMS\Core\Utility\ExtensionManagementUtility::tcaIsBeingBuilt`
+- :php:`TYPO3\CMS\Install\Service\SqlExpectedSchemaService::tablesDefinitionIsBeingBuilt`
+- :php:`TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::PostProcessTreeData`
+
+
+Impact
+======
+
+It is now possible to add listeners to the new PSR-14 Events which
+define a clear API what can be read or modified.
+
+The listeners can be added to the :file:`Configuration/Services.yaml` as
+it is done in TYPO3's shipped extensions as well.
+
+.. index:: PHP-API, ext:core
index cc1c206..819f9af 100644 (file)
@@ -22,10 +22,10 @@ use Doctrine\DBAL\Schema\Table;
 use Doctrine\DBAL\Types\IntegerType;
 use Doctrine\DBAL\Types\SmallIntType;
 use Doctrine\DBAL\Types\TextType;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Database\Schema\Parser\Parser;
 use TYPO3\CMS\Core\Database\Schema\SqlReader;
 use TYPO3\CMS\Core\Package\PackageManager;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 /**
@@ -50,9 +50,9 @@ class TableBuilderTest extends UnitTestCase
     {
         parent::setUp();
         $sqlFile = file_get_contents(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Fixtures', 'tablebuilder.sql']));
-        $signalSlotDispatcherProphecy = $this->prophesize(Dispatcher::class);
+        $eventDispatcherProphecy = $this->prophesize(EventDispatcherInterface::class);
         $packageManagerProphecy = $this->prophesize(PackageManager::class);
-        $sqlReader = new SqlReader($signalSlotDispatcherProphecy->reveal(), $packageManagerProphecy->reveal());
+        $sqlReader = new SqlReader($eventDispatcherProphecy->reveal(), $packageManagerProphecy->reveal());
         $statements = $sqlReader->getCreateTableStatementArray($sqlFile);
 
         $parser = new Parser($statements[0]);
index 588ae25..9c64f6f 100644 (file)
@@ -16,9 +16,9 @@ namespace TYPO3\CMS\Core\Tests\Unit\Database\Schema;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Database\Schema\SqlReader;
 use TYPO3\CMS\Core\Package\PackageManager;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 /**
@@ -36,7 +36,7 @@ class SqlReaderTest extends UnitTestCase
      */
     public function getStatementArraySplitsStatements()
     {
-        $subject = new SqlReader($this->prophesize(Dispatcher::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
+        $subject = new SqlReader($this->prophesize(EventDispatcherInterface::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
         $result = $subject->getStatementArray(
             'CREATE TABLE aTestTable(' . LF . '  aTestField INT(11)' . LF . ');' .
             LF .
@@ -52,7 +52,7 @@ class SqlReaderTest extends UnitTestCase
      */
     public function getStatementArrayFiltersStatements()
     {
-        $subject = new SqlReader($this->prophesize(Dispatcher::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
+        $subject = new SqlReader($this->prophesize(EventDispatcherInterface::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
         $result = $subject->getStatementArray(
             'CREATE TABLE aTestTable(' . LF . '  aTestField INT(11)' . LF . ');' .
             LF .
@@ -68,7 +68,7 @@ class SqlReaderTest extends UnitTestCase
      */
     public function getInsertStatementArrayResult()
     {
-        $subject = new SqlReader($this->prophesize(Dispatcher::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
+        $subject = new SqlReader($this->prophesize(EventDispatcherInterface::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
         $result = $subject->getInsertStatementArray(
             'CREATE TABLE aTestTable(' . LF . '  aTestField INT(11)' . LF . ');' .
             LF .
@@ -84,7 +84,7 @@ class SqlReaderTest extends UnitTestCase
      */
     public function getInsertStatementArrayResultWithNewline()
     {
-        $subject = new SqlReader($this->prophesize(Dispatcher::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
+        $subject = new SqlReader($this->prophesize(EventDispatcherInterface::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
         $result = $subject->getInsertStatementArray(
             'CREATE TABLE aTestTable(' . LF . '  aTestField INT(11)' . LF . ');' .
             LF .
@@ -102,7 +102,7 @@ class SqlReaderTest extends UnitTestCase
      */
     public function getCreateTableStatementArrayResult()
     {
-        $subject = new SqlReader($this->prophesize(Dispatcher::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
+        $subject = new SqlReader($this->prophesize(EventDispatcherInterface::class)->reveal(), $this->prophesize(PackageManager::class)->reveal());
         $result = $subject->getCreateTableStatementArray(
             'CREATE TABLE aTestTable(' . LF . '  aTestField INT(11)' . LF . ');' .
             LF .
index 09a1b7e..c1049d3 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Database;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Database\SoftReferenceIndex;
 use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Resource\Folder;
@@ -212,8 +213,9 @@ class SoftReferenceIndexTest extends UnitTestCase
      */
     public function findRefReturnsParsedElements(array $softrefConfiguration, array $expectedElement)
     {
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
         foreach ($softrefConfiguration as $softrefKey => $configuration) {
-            $subject = new SoftReferenceIndex();
+            $subject = new SoftReferenceIndex($eventDispatcher->reveal());
             $result = $subject->findRef(
                 'tt_content',
                 'bodytext',
@@ -331,8 +333,9 @@ class SoftReferenceIndexTest extends UnitTestCase
 
         GeneralUtility::setSingletonInstance(ResourceFactory::class, $resourceFactory->reveal());
 
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
         foreach ($softrefConfiguration as $softrefKey => $configuration) {
-            $subject = new SoftReferenceIndex();
+            $subject = new SoftReferenceIndex($eventDispatcher->reveal());
             $result = $subject->findRef(
                 'tt_content',
                 'bodytext',
@@ -389,8 +392,9 @@ class SoftReferenceIndexTest extends UnitTestCase
         $resourceFactory->getFolderObjectFromCombinedIdentifier('1:/foo/bar/baz')->willReturn($folderObject->reveal())->shouldBeCalledTimes(count($softrefConfiguration));
         GeneralUtility::setSingletonInstance(ResourceFactory::class, $resourceFactory->reveal());
 
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
         foreach ($softrefConfiguration as $softrefKey => $configuration) {
-            $subject = new SoftReferenceIndex();
+            $subject = new SoftReferenceIndex($eventDispatcher->reveal());
             $result = $subject->findRef(
                 'tt_content',
                 'bodytext',
@@ -428,8 +432,9 @@ class SoftReferenceIndexTest extends UnitTestCase
      */
     public function getTypoLinkPartsThrowExceptionWithPharReferences(string $pharUrl)
     {
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1530030672);
-        (new SoftReferenceIndex())->getTypoLinkParts($pharUrl);
+        (new SoftReferenceIndex($eventDispatcher->reveal()))->getTypoLinkParts($pharUrl);
     }
 }
index bee3d6b..30ade51 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Imaging;
  */
 
 use Prophecy\Argument;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Imaging\IconProvider\FontawesomeIconProvider;
@@ -23,8 +24,6 @@ use TYPO3\CMS\Core\Imaging\IconRegistry;
 use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Resource\Folder;
 use TYPO3\CMS\Core\Resource\ResourceStorage;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 /**
@@ -90,11 +89,10 @@ class IconFactoryTest extends UnitTestCase
     {
         parent::setUp();
         $this->iconRegistryMock = $this->prophesize(IconRegistry::class);
-        $signalSlotDispatcherMock = $this->prophesize(SignalSlotDispatcher::class);
-        $signalSlotDispatcherMock->dispatch(Argument::any(), Argument::any(), Argument::type('array'))->willReturnArgument(2);
-        GeneralUtility::setSingletonInstance(SignalSlotDispatcher::class, $signalSlotDispatcherMock->reveal());
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+        $eventDispatcher->dispatch(Argument::any())->willReturnArgument(0);
 
-        $this->subject = new IconFactory($this->iconRegistryMock->reveal());
+        $this->subject = new IconFactory($eventDispatcher->reveal(), $this->iconRegistryMock->reveal());
 
         $this->iconRegistryMock->isRegistered('tcarecords--default')->willReturn(false);
         $this->iconRegistryMock->isRegistered(Argument::any())->willReturn(true);
index b1654c0..77bf1b8 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Imaging;
  */
 
 use Prophecy\Argument;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
 use TYPO3\CMS\Core\Imaging\Icon;
@@ -55,7 +56,8 @@ class IconTest extends UnitTestCase
         $cacheManagerProphecy->getCache('assets')->willReturn($cacheFrontendProphecy->reveal());
         $cacheFrontendProphecy->get(Argument::cetera())->willReturn(false);
         $cacheFrontendProphecy->set(Argument::cetera())->willReturn(null);
-        $iconFactory = new IconFactory();
+        $eventDispatcherProphecy = $this->prophesize(EventDispatcherInterface::class);
+        $iconFactory = new IconFactory($eventDispatcherProphecy->reveal());
         $this->subject = $iconFactory->getIcon($this->iconIdentifier, Icon::SIZE_SMALL, $this->overlayIdentifier, IconState::cast(IconState::STATE_DISABLED));
     }
 
index eab49a0..8806996 100644 (file)
@@ -15,9 +15,12 @@ namespace TYPO3\CMS\Core\Tests\Unit\Tree\TableConfiguration;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\DependencyInjection\FailsafeContainer;
 use TYPO3\CMS\Core\Tests\Unit\Tree\TableConfiguration\Fixtures\TreeDataProviderFixture;
 use TYPO3\CMS\Core\Tests\Unit\Tree\TableConfiguration\Fixtures\TreeDataProviderWithConfigurationFixture;
+use TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider;
 use TYPO3\CMS\Core\Tree\TableConfiguration\TreeDataProviderFactory;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 /**
@@ -25,15 +28,9 @@ use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
  */
 class TreeDataProviderFactoryTest extends UnitTestCase
 {
-    /**
-     * @var TreeDataProviderFactory
-     */
-    protected $subject;
-
     protected function setUp(): void
     {
         parent::setUp();
-        $this->subject = new TreeDataProviderFactory();
         $GLOBALS['TCA'] = [];
         $GLOBALS['TCA']['foo'] = [];
         $GLOBALS['TCA']['foo']['ctrl'] = [];
@@ -96,10 +93,15 @@ class TreeDataProviderFactoryTest extends UnitTestCase
      */
     public function factoryThrowsExceptionIfInvalidConfigurationIsGiven(array $tcaConfiguration, int $expectedExceptionCode): void
     {
+        $treeDataProvider = $this->prophesize(DatabaseTreeDataProvider::class);
+        GeneralUtility::setContainer(new FailsafeContainer([], [
+            DatabaseTreeDataProvider::class => $treeDataProvider->reveal()
+        ]));
+
         $this->expectException(\InvalidArgumentException::class);
         $this->expectExceptionCode($expectedExceptionCode);
 
-        $this->subject::getDataProvider($tcaConfiguration, 'foo', 'bar', ['uid' => 1]);
+        TreeDataProviderFactory::getDataProvider($tcaConfiguration, 'foo', 'bar', ['uid' => 1]);
     }
 
     /**
@@ -113,7 +115,7 @@ class TreeDataProviderFactoryTest extends UnitTestCase
             'treeConfig' => ['dataProvider' => $dataProviderMockClassName],
             'internal_type' => 'foo'
         ];
-        $dataProvider = $this->subject::getDataProvider($tcaConfiguration, 'foo', 'bar', ['uid' => 1]);
+        $dataProvider = TreeDataProviderFactory::getDataProvider($tcaConfiguration, 'foo', 'bar', ['uid' => 1]);
 
         self::assertInstanceOf($dataProviderMockClassName, $dataProvider);
     }
@@ -133,6 +135,6 @@ class TreeDataProviderFactoryTest extends UnitTestCase
         ];
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1438875249);
-        $this->subject::getDataProvider($tcaConfiguration, 'foo', 'bar', ['uid' => 1]);
+        TreeDataProviderFactory::getDataProvider($tcaConfiguration, 'foo', 'bar', ['uid' => 1]);
     }
 }
index 1095a46..d2e430b 100644 (file)
@@ -17,7 +17,6 @@ namespace TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 
 /**
  * Accessible proxy with protected methods made public
@@ -29,11 +28,6 @@ class ExtensionManagementUtilityAccessibleProxy extends ExtensionManagementUtili
         static::$cacheManager = $cacheManager;
     }
 
-    public static function setSignalSlotDispatcher(Dispatcher $dispatcher = null)
-    {
-        static::$signalSlotDispatcher = $dispatcher;
-    }
-
     public static function getPackageManager()
     {
         return static::$packageManager;
@@ -79,7 +73,7 @@ class ExtensionManagementUtilityAccessibleProxy extends ExtensionManagementUtili
         $GLOBALS['TCA'] = [];
     }
 
-    public static function emitTcaIsBeingBuiltSignal(array $tca)
+    public static function dispatchTcaIsBeingBuiltEvent(array $tca)
     {
     }
 
index 3eb22c1..2096ace 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Core\Tests\Unit\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Prophecy\Argument;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
 use TYPO3\CMS\Core\Category\CategoryRegistry;
@@ -24,7 +26,6 @@ use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 /**
@@ -58,7 +59,6 @@ class ExtensionManagementUtilityTest extends UnitTestCase
     {
         ExtensionManagementUtilityAccessibleProxy::setPackageManager($this->backUpPackageManager);
         ExtensionManagementUtilityAccessibleProxy::setCacheManager(null);
-        ExtensionManagementUtilityAccessibleProxy::setSignalSlotDispatcher(null);
         parent::tearDown();
     }
 
@@ -1455,9 +1455,9 @@ class ExtensionManagementUtilityTest extends UnitTestCase
         $mockCache->expects(self::once())->method('require')->willReturn(false);
         $mockCache->expects(self::once())->method('set')->with(self::anything(), self::stringContains($uniqueStringInTableConfiguration), self::anything());
 
-        $mockSignalSlotDispatcher = $this->createMock(SignalSlotDispatcher::class);
-        $mockSignalSlotDispatcher->expects(self::once())->method('dispatch')->with(self::anything(), self::anything(), self::isType('array'))->willReturnArgument(2);
-        ExtensionManagementUtilityAccessibleProxy::setSignalSlotDispatcher($mockSignalSlotDispatcher);
+        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+        $eventDispatcher->dispatch(Argument::any())->shouldBeCalled()->willReturnArgument(0);
+        ExtensionManagementUtility::setEventDispatcher($eventDispatcher->reveal());
 
         ExtensionManagementUtility::loadBaseTca(true);
     }
index da2d253..3282bfb 100644 (file)
@@ -38,19 +38,6 @@ if (!\TYPO3\CMS\Core\Core\Environment::isComposerMode()) {
     );
 }
 
-$signalSlotDispatcher->connect(
-    'TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService',
-    'tablesDefinitionIsBeingBuilt',
-    \TYPO3\CMS\Core\Cache\DatabaseSchemaService::class,
-    'addCachingFrameworkRequiredDatabaseSchemaForSqlExpectedSchemaService'
-);
-$signalSlotDispatcher->connect(
-    'TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService',
-    'tablesDefinitionIsBeingBuilt',
-    \TYPO3\CMS\Core\Category\CategoryRegistry::class,
-    'addCategoryDatabaseSchemaToTablesDefinition'
-);
-
 unset($signalSlotDispatcher);
 
 $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['dumpFile'] = \TYPO3\CMS\Core\Controller\FileDumpController::class . '::dumpAction';
index effd14f..4d1df2e 100644 (file)
@@ -17,6 +17,14 @@ namespace TYPO3\CMS\Extbase\SignalSlot;
  */
 
 use Psr\Log\LoggerInterface;
+use TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent;
+use TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent;
+use TYPO3\CMS\Core\Database\ReferenceIndex;
+use TYPO3\CMS\Core\Database\SoftReferenceIndex;
+use TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent;
+use TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent;
+use TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent;
+use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Resource\Event\AfterFileAddedEvent;
 use TYPO3\CMS\Core\Resource\Event\AfterFileAddedToIndexEvent;
 use TYPO3\CMS\Core\Resource\Event\AfterFileContentsSetEvent;
@@ -64,6 +72,9 @@ use TYPO3\CMS\Core\Resource\ResourceFactoryInterface;
 use TYPO3\CMS\Core\Resource\ResourceStorage;
 use TYPO3\CMS\Core\Resource\ResourceStorageInterface;
 use TYPO3\CMS\Core\Resource\Service\FileProcessingService;
+use TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent;
+use TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
 
 /**
@@ -143,6 +154,24 @@ class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface
             FileProcessingService::SIGNAL_PreFileProcess => BeforeFileProcessingEvent::class,
             FileProcessingService::SIGNAL_PostFileProcess => AfterFileProcessingEvent::class,
         ],
+        IconFactory::class => [
+            'buildIconForResourceSignal' => ModifyIconForResourcePropertiesEvent::class,
+        ],
+        SoftReferenceIndex::class => [
+            'setTypoLinkPartsElement' => AppendLinkHandlerElementsEvent::class,
+        ],
+        ReferenceIndex::class => [
+            'shouldExcludeTableFromReferenceIndex' => IsTableExcludedFromReferenceIndexEvent::class,
+        ],
+        ExtensionManagementUtility::class => [
+            'tcaIsBeingBuilt' => AfterTcaCompilationEvent::class,
+        ],
+        'TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService' => [
+            'tablesDefinitionIsBeingBuilt' => AlterTableDefinitionStatementsEvent::class,
+        ],
+        DatabaseTreeDataProvider::class => [
+            'PostProcessTreeData' => ModifyTreeDataEvent::class,
+        ],
     ];
 
     /**
index b700bb5..42520e1 100644 (file)
@@ -13,34 +13,34 @@ namespace TYPO3\CMS\IndexedSearch\Service;
  *
  * The TYPO3 project - inspiring people to share!
  */
+
 use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
+use TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * This service provides the mysql specific changes of the schema definition
  * @internal this is a TYPO3-internal hook implementation and not part of TYPO3's Core API.
  */
-class DatabaseSchemaService
+final class DatabaseSchemaService
 {
     /**
-     * A slot method to inject the required mysql fulltext definition
-     * to schema migration
+     * A event listener to inject the required mysql fulltext definition
+     * to schema migration.
      *
-     * @param array $sqlString
-     * @return array
+     * @param AlterTableDefinitionStatementsEvent $event
      */
-    public function addMysqlFulltextIndex(array $sqlString)
+    public function addMysqlFulltextIndex(AlterTableDefinitionStatementsEvent $event): void
     {
         $useMysqlFulltext = (bool)GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('indexed_search', 'useMysqlFulltext');
         if ($useMysqlFulltext) {
             // @todo: With MySQL 5.7 fulltext index on InnoDB is possible, check for that and keep inno if so.
-            $sqlString[] = 'CREATE TABLE index_fulltext ('
+            $event->addSqlData('CREATE TABLE index_fulltext ('
                 . LF . 'fulltextdata mediumtext,'
                 . LF . 'metaphonedata mediumtext,'
                 . LF . 'FULLTEXT fulltextdata (fulltextdata),'
                 . LF . 'FULLTEXT metaphonedata (metaphonedata)'
-                . LF . ') ENGINE=MyISAM;';
+                . LF . ') ENGINE=MyISAM;');
         }
-        return [$sqlString];
     }
 }
index 66394f0..4f45491 100644 (file)
@@ -6,3 +6,10 @@ services:
 
   TYPO3\CMS\IndexedSearch\:
     resource: '../Classes/*'
+
+  TYPO3\CMS\IndexedSearch\Service\DatabaseSchemaService:
+    tags:
+      - name: event.listener
+        identifier: 'indexed-search'
+        method: 'addMysqlFulltextIndex'
+        event: TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent
index 25e9025..51ffb6c 100644 (file)
@@ -60,15 +60,6 @@ if (isset($extConf['useMysqlFulltext']) && (bool)$extConf['useMysqlFulltext']) {
     // Use all index_* tables except "index_rel" and "index_words"
     $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['use_tables'] =
         'index_phash,index_fulltext,index_section,index_grlist,index_stat_search,index_stat_word,index_debug,index_config';
-    // Register schema analyzer slot to hook in required fulltext index definition
-    $signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
-    $signalSlotDispatcher->connect(
-        'TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService',
-        'tablesDefinitionIsBeingBuilt',
-        \TYPO3\CMS\IndexedSearch\Service\DatabaseSchemaService::class,
-        'addMysqlFulltextIndex'
-    );
-    unset($signalSlotDispatcher);
 } else {
     $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['use_tables'] =
         'index_phash,index_fulltext,index_rel,index_words,index_section,index_grlist,index_stat_search,index_stat_word,index_debug,index_config';
index 598ad31..fe7223d 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Install\Service;
  */
 
 use Psr\Container\ContainerInterface;
+use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Core\Bootstrap;
 use TYPO3\CMS\Core\DependencyInjection\ContainerBuilder;
 use TYPO3\CMS\Core\Imaging\IconRegistry;
@@ -125,6 +126,8 @@ class LateBootService
         $assetsCache = $container->get('cache.assets');
         IconRegistry::setCache($assetsCache);
         PageRenderer::setCache($assetsCache);
+        $eventDispatcher = $container->get(EventDispatcherInterface::class);
+        ExtensionManagementUtility::setEventDispatcher($eventDispatcher);
         Bootstrap::loadTypo3LoadedExtAndExtLocalconf(false);
         Bootstrap::unsetReservedGlobalVariables();
         $container->get('boot.state')->done = true;
index 4b31f1d..c3b01d1 100644 (file)
@@ -351,5 +351,11 @@ return [
         'restFiles' => [
             'Deprecation-89577-FALSignalSlotHandlingMigratedToPSR-14Events.rst',
         ],
+    ],
+    'TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::SIGNAL_PostProcessTreeData' => [
+        'restFiles' => [
+            'Feature-89733-NewPSR-14EventsForExistingSignalSlotsInCoreExtension.rst',
+            'Deprecation-89733-SignalSlotsInCoreExtensionMigratedToPSR-14Events.rst',
+        ],
     ]
 ];