diff --git a/typo3/sysext/core/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/core/Classes/Compatibility/SlotReplacement.php index d2f22b9aeb9e92163b43d0395377448cd6fe2e1e..63a8316387e356aae598df6e96ae5bf701efc457 100644 --- a/typo3/sysext/core/Classes/Compatibility/SlotReplacement.php +++ b/typo3/sysext/core/Classes/Compatibility/SlotReplacement.php @@ -27,6 +27,7 @@ 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\Package\Event\PackagesMayHaveChangedEvent; use TYPO3\CMS\Core\Resource\Event\AfterFileAddedEvent; use TYPO3\CMS\Core\Resource\Event\AfterFileAddedToIndexEvent; use TYPO3\CMS\Core\Resource\Event\AfterFileContentsSetEvent; @@ -681,4 +682,9 @@ class SlotReplacement ); } } + + public function packagesMayHaveChanged(PackagesMayHaveChangedEvent $event): void + { + $this->signalSlotDispatcher->dispatch('PackageManagement', 'packagesMayHaveChanged'); + } } diff --git a/typo3/sysext/core/Classes/Core/ClassLoadingInformation.php b/typo3/sysext/core/Classes/Core/ClassLoadingInformation.php index a0686c4472125e68e721947bbf7d9f934d8a34c1..f00b6ccc5af774cdc90c167b024794da154e7439 100644 --- a/typo3/sysext/core/Classes/Core/ClassLoadingInformation.php +++ b/typo3/sysext/core/Classes/Core/ClassLoadingInformation.php @@ -16,6 +16,8 @@ namespace TYPO3\CMS\Core\Core; use Composer\Autoload\ClassLoader; use TYPO3\ClassAliasLoader\ClassAliasMap; +use TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent; +use TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent; use TYPO3\CMS\Core\Package\PackageInterface; use TYPO3\CMS\Core\Package\PackageManager; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -101,6 +103,30 @@ class ClassLoadingInformation GeneralUtility::writeFile(self::getClassLoadingInformationDirectory() . self::AUTOLOAD_CLASSALIASMAP_FILENAME, $classAliasMapFile); } + /** + * @param AfterPackageDeactivationEvent $event + * @internal + */ + public static function updateClassLoadingInformationAfterPackageDeactivation(AfterPackageDeactivationEvent $event): void + { + if (Environment::isComposerMode()) { + return; + } + static::dumpClassLoadingInformation(); + } + + /** + * @param AfterPackageActivationEvent $event + * @internal + */ + public static function updateClassLoadingInformationAfterPackageActivation(AfterPackageActivationEvent $event): void + { + if (Environment::isComposerMode()) { + return; + } + static::dumpClassLoadingInformation(); + } + /** * Registers the class aliases, the class maps and the PSR4 prefixes previously identified by * the ClassLoadingInformationGenerator during runtime. diff --git a/typo3/sysext/core/Classes/Package/Event/AfterPackageActivationEvent.php b/typo3/sysext/core/Classes/Package/Event/AfterPackageActivationEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..03cffa94ede979d52f2726bdafef4d9fd35e91b5 --- /dev/null +++ b/typo3/sysext/core/Classes/Package/Event/AfterPackageActivationEvent.php @@ -0,0 +1,59 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Core\Package\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 that is triggered after a package has been activated + */ +final class AfterPackageActivationEvent +{ + /** + * @var string + */ + private $packageKey; + + /** + * @var string + */ + private $type; + + /** + * @var object + */ + private $emitter; + + public function __construct(string $packageKey, string $type, object $emitter = null) + { + $this->packageKey = $packageKey; + $this->type = $type; + $this->emitter = $emitter; + } + + public function getPackageKey(): string + { + return $this->packageKey; + } + + public function getType(): string + { + return $this->type; + } + + public function getEmitter(): object + { + return $this->emitter; + } +} diff --git a/typo3/sysext/core/Classes/Package/Event/AfterPackageDeactivationEvent.php b/typo3/sysext/core/Classes/Package/Event/AfterPackageDeactivationEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..fb95d64f009a8a1bdc41b6c0722d71fb3fb63c67 --- /dev/null +++ b/typo3/sysext/core/Classes/Package/Event/AfterPackageDeactivationEvent.php @@ -0,0 +1,59 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Core\Package\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 that is triggered after a package has been de-activated + */ +final class AfterPackageDeactivationEvent +{ + /** + * @var string + */ + private $packageKey; + + /** + * @var string + */ + private $type; + + /** + * @var object + */ + private $emitter; + + public function __construct(string $packageKey, string $type, object $emitter = null) + { + $this->packageKey = $packageKey; + $this->type = $type; + $this->emitter = $emitter; + } + + public function getPackageKey(): string + { + return $this->packageKey; + } + + public function getType(): string + { + return $this->type; + } + + public function getEmitter(): object + { + return $this->emitter; + } +} diff --git a/typo3/sysext/core/Classes/Package/Event/BeforePackageActivationEvent.php b/typo3/sysext/core/Classes/Package/Event/BeforePackageActivationEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..fccff637e1f4f17a3616fd37fc00dc75be97fc75 --- /dev/null +++ b/typo3/sysext/core/Classes/Package/Event/BeforePackageActivationEvent.php @@ -0,0 +1,37 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Core\Package\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 that is triggered before a number of packages should become active + */ +final class BeforePackageActivationEvent +{ + /** + * @var array + */ + private $packageKeys; + + public function __construct(array $packageKeys) + { + $this->packageKeys = $packageKeys; + } + + public function getPackageKeys(): array + { + return $this->packageKeys; + } +} diff --git a/typo3/sysext/core/Classes/Package/Event/PackagesMayHaveChangedEvent.php b/typo3/sysext/core/Classes/Package/Event/PackagesMayHaveChangedEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..fd404bfedd3e061f55e03797f0227c64b7786e2b --- /dev/null +++ b/typo3/sysext/core/Classes/Package/Event/PackagesMayHaveChangedEvent.php @@ -0,0 +1,23 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Core\Package\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! + */ + +/** + * Marker event to ensure that Core is re-triggering the package ordering and package listings + */ +final class PackagesMayHaveChangedEvent +{ +} diff --git a/typo3/sysext/core/Classes/Package/PackageManager.php b/typo3/sysext/core/Classes/Package/PackageManager.php index 3c135d611ef8f0d1f6baf7b1a9641d85be1be56b..8b6b97f5cda9b77632fa6778c4dd736cc9a67a04 100644 --- a/typo3/sysext/core/Classes/Package/PackageManager.php +++ b/typo3/sysext/core/Classes/Package/PackageManager.php @@ -20,6 +20,8 @@ use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Core\Core\ClassLoadingInformation; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Information\Typo3Version; +use TYPO3\CMS\Core\Package\Event\BeforePackageActivationEvent; +use TYPO3\CMS\Core\Package\Event\PackagesMayHaveChangedEvent; use TYPO3\CMS\Core\Service\DependencyOrderingService; use TYPO3\CMS\Core\Service\OpcodeCacheService; use TYPO3\CMS\Core\SingletonInterface; @@ -291,6 +293,23 @@ class PackageManager implements SingletonInterface $this->registerPackagesFromConfiguration($packages, $registerOnlyNewPackages); } + /** + * Event listener to retrigger scanning of available packages. + * + * @param PackagesMayHaveChangedEvent $event + */ + public function packagesMayHaveChanged(PackagesMayHaveChangedEvent $event): void + { + $this->scanAvailablePackages(); + } + + public function beforeInstallationEventListener(BeforePackageActivationEvent $event): void + { + if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_BE) { + $this->scanAvailablePackages(); + } + } + /** * Scans all directories for a certain package. * diff --git a/typo3/sysext/core/Configuration/Services.yaml b/typo3/sysext/core/Configuration/Services.yaml index 862459f43256a872695b4f12cc2e10360cf83875..8ec4c77b7b5119a906fcf23873fff1f3f4fc7f7f 100644 --- a/typo3/sysext/core/Configuration/Services.yaml +++ b/typo3/sysext/core/Configuration/Services.yaml @@ -16,6 +16,11 @@ services: TYPO3\CMS\Core\Package\PackageManager: autoconfigure: false + tags: + - name: event.listener + identifier: 'typo3-core' + method: 'packagesMayHaveChanged' + event: TYPO3\CMS\Core\Package\Event\PackagesMayHaveChangedEvent TYPO3\CMS\Core\Package\FailsafePackageManager: autoconfigure: false @@ -38,6 +43,18 @@ services: TYPO3\CMS\Core\Mail\Mailer: public: true + TYPO3\CMS\Core\Core\ClassLoadingInformation: + public: false + tags: + - name: event.listener + identifier: 'non-composer-class-loader' + method: 'updateClassLoadingInformationAfterPackageActivation' + event: TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent + - name: event.listener + identifier: 'non-composer-class-loader' + method: 'updateClassLoadingInformationAfterPackageDeactivation' + event: TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent + TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider: shared: false public: true @@ -235,6 +252,10 @@ services: identifier: 'legacy-slot' method: 'onDatabaseTreeDataProviderEmitPostProcessTreeDataSignal' event: TYPO3\CMS\Core\Tree\Event\ModifyTreeDataEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'packagesMayHaveChanged' + event: TYPO3\CMS\Core\Package\Event\PackagesMayHaveChangedEvent # FAL security checks for backend users TYPO3\CMS\Core\Resource\Security\StoragePermissionsAspect: diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-90249-PackageRelatedSignalSlotsMigratedToPSR-14Events.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-90249-PackageRelatedSignalSlotsMigratedToPSR-14Events.rst new file mode 100644 index 0000000000000000000000000000000000000000..6faac192a2436e7af14fdadd1cf2568cc278c08d --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-90249-PackageRelatedSignalSlotsMigratedToPSR-14Events.rst @@ -0,0 +1,50 @@ +.. include:: ../../Includes.txt + +============================================================================ +Deprecation: #90249 - Package related Signal Slots migrated to PSR-14 events +============================================================================ + +See :issue:`90249` + +Description +=========== + +The following Signal Slots have been replaced by new PSR-14 events +which can be used as 1:1 equivalents: + +- :php:`PackageManagement::packagesMayHaveChanged` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionInstall` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionUninstall` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionT3DImport` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionStaticSqlImport` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionFileImport` +- :php:`TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService::willInstallExtensions` +- :php:`TYPO3\CMS\Extensionmanager\ViewHelper\ProcessAvailableActionsViewHelper::processActions` + +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\Package\Event\PackagesMayHaveChangedEvent` +- :php:`TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent` +- :php:`TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent` +- :php:`TYPO3\CMS\Core\Package\Event\BeforePackageActivationEvent` +- :php:`TYPO3\CMS\Extensionmanager\Event\AfterExtensionDatabaseContentHasBeenImportedEvent` +- :php:`TYPO3\CMS\Extensionmanager\Event\AfterExtensionStaticDatabaseContentHasBeenImportedEvent` +- :php:`TYPO3\CMS\Extensionmanager\Event\AfterExtensionFilesHaveBeenImportedEvent` +- :php:`TYPO3\CMS\Extensionmanager\Event\AvailableActionsForExtensionEvent` + +.. index:: PHP-API, FullyScanned, ext:core diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-90249-NewPSR-14EventsForExistingPackage-relatedSignalSlots.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-90249-NewPSR-14EventsForExistingPackage-relatedSignalSlots.rst new file mode 100644 index 0000000000000000000000000000000000000000..c9ef71eb3e38120a28e1fb1cb853b1e205059a89 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-90249-NewPSR-14EventsForExistingPackage-relatedSignalSlots.rst @@ -0,0 +1,46 @@ +.. include:: ../../Includes.txt + +============================================================================= +Feature: #90249 - New PSR-14 events for existing package-related Signal Slots +============================================================================= + +See :issue:`90249` + +Description +=========== + +PSR-14-based event dispatching 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\Package\Event\PackagesMayHaveChangedEvent` +- :php:`TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent` +- :php:`TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent` +- :php:`TYPO3\CMS\Core\Package\Event\BeforePackageActivationEvent` +- :php:`TYPO3\CMS\Extensionmanager\Event\AfterExtensionDatabaseContentHasBeenImportedEvent` +- :php:`TYPO3\CMS\Extensionmanager\Event\AfterExtensionStaticDatabaseContentHasBeenImportedEvent` +- :php:`TYPO3\CMS\Extensionmanager\Event\AfterExtensionFilesHaveBeenImportedEvent` +- :php:`TYPO3\CMS\Extensionmanager\Event\AvailableActionsForExtensionEvent` + +They replace the existing Extbase-based Signal Slots: + +- :php:`PackageManagement::packagesMayHaveChanged` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionInstall` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionUninstall` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionT3DImport` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionStaticSqlImport` +- :php:`TYPO3\CMS\Extensionmanager\Utility\InstallUtility::afterExtensionFileImport` +- :php:`TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService::willInstallExtensions` +- :php:`TYPO3\CMS\Extensionmanager\ViewHelper\ProcessAvailableActionsViewHelper::processActions` + +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 diff --git a/typo3/sysext/core/ext_localconf.php b/typo3/sysext/core/ext_localconf.php index 3282bfb82620eaf12044c609b10f2a46c7eb9b6a..478ea0cf6d1cc2a7576ea31f806ce371aec9dca6 100644 --- a/typo3/sysext/core/ext_localconf.php +++ b/typo3/sysext/core/ext_localconf.php @@ -2,17 +2,6 @@ defined('TYPO3_MODE') or die(); -/** @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher */ -$signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class); - -// PACKAGE MANAGEMENT -$signalSlotDispatcher->connect( - 'PackageManagement', - 'packagesMayHaveChanged', - \TYPO3\CMS\Core\Package\PackageManager::class, - 'scanAvailablePackages' -); - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = \TYPO3\CMS\Core\Resource\Security\FileMetadataPermissionsAspect::class; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = \TYPO3\CMS\Core\Hooks\BackendUserGroupIntegrityCheck::class; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = \TYPO3\CMS\Core\Hooks\BackendUserPasswordCheck::class; @@ -22,24 +11,6 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['chec $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = \TYPO3\CMS\Core\Hooks\DestroySessionHook::class; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = \TYPO3\CMS\Core\Hooks\PagesTsConfigGuard::class; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][\TYPO3\CMS\Core\Hooks\CreateSiteConfiguration::class] = \TYPO3\CMS\Core\Hooks\CreateSiteConfiguration::class; - -if (!\TYPO3\CMS\Core\Core\Environment::isComposerMode()) { - $signalSlotDispatcher->connect( - \TYPO3\CMS\Extensionmanager\Utility\InstallUtility::class, - 'afterExtensionInstall', - \TYPO3\CMS\Core\Core\ClassLoadingInformation::class, - 'dumpClassLoadingInformation' - ); - $signalSlotDispatcher->connect( - \TYPO3\CMS\Extensionmanager\Utility\InstallUtility::class, - 'afterExtensionUninstall', - \TYPO3\CMS\Core\Core\ClassLoadingInformation::class, - 'dumpClassLoadingInformation' - ); -} - -unset($signalSlotDispatcher); - $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['dumpFile'] = \TYPO3\CMS\Core\Controller\FileDumpController::class . '::dumpAction'; $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['requirejs'] = \TYPO3\CMS\Core\Controller\RequireJsController::class . '::retrieveConfiguration'; diff --git a/typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php b/typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php index 7010bbda7e3585abb7ab47f27aecd00792ef76ec..c4d88e18878c889abbb3e699d5e0756bce69ed5a 100644 --- a/typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php +++ b/typo3/sysext/extbase/Classes/SignalSlot/Dispatcher.php @@ -35,6 +35,10 @@ 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\Package\Event\AfterPackageActivationEvent; +use TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent; +use TYPO3\CMS\Core\Package\Event\BeforePackageActivationEvent; +use TYPO3\CMS\Core\Package\Event\PackagesMayHaveChangedEvent; use TYPO3\CMS\Core\Resource\Event\AfterFileAddedEvent; use TYPO3\CMS\Core\Resource\Event\AfterFileAddedToIndexEvent; use TYPO3\CMS\Core\Resource\Event\AfterFileContentsSetEvent; @@ -99,6 +103,13 @@ use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Extbase\Persistence\Generic\Backend; use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionDatabaseContentHasBeenImportedEvent; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionFilesHaveBeenImportedEvent; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionStaticDatabaseContentHasBeenImportedEvent; +use TYPO3\CMS\Extensionmanager\Event\AvailableActionsForExtensionEvent; +use TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService; +use TYPO3\CMS\Extensionmanager\Utility\InstallUtility; +use TYPO3\CMS\Extensionmanager\ViewHelpers\ProcessAvailableActionsViewHelper; /** * A dispatcher which dispatches signals by calling its registered slot methods @@ -250,6 +261,22 @@ class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface 'generateDataArray.postProcess' => 'TYPO3\\CMS\\Workspaces\\Event\\AfterDataGeneratedForWorkspaceEvent', 'getDataArray.postProcess' => 'TYPO3\\CMS\\Workspaces\\Event\\GetVersionedDataEvent', 'sortDataArray.postProcess' => 'TYPO3\\CMS\\Workspaces\\Event\\SortVersionedDataEvent', + ], + 'PackageManagement' => [ + 'packagesMayHaveChanged' => PackagesMayHaveChangedEvent::class, + ], + InstallUtility::class => [ + 'afterExtensionInstall' => AfterPackageActivationEvent::class, + 'afterExtensionUninstall' => AfterPackageDeactivationEvent::class, + 'afterExtensionT3DImport' => AfterExtensionDatabaseContentHasBeenImportedEvent::class, + 'afterExtensionStaticSqlImport' => AfterExtensionStaticDatabaseContentHasBeenImportedEvent::class, + 'afterExtensionFileImport' => AfterExtensionFilesHaveBeenImportedEvent::class, + ], + ExtensionManagementService::class => [ + 'willInstallExtensions' => BeforePackageActivationEvent::class + ], + ProcessAvailableActionsViewHelper::class => [ + 'processActions' => AvailableActionsForExtensionEvent::class ] ]; diff --git a/typo3/sysext/extensionmanager/Classes/Command/ActivateExtensionCommand.php b/typo3/sysext/extensionmanager/Classes/Command/ActivateExtensionCommand.php index 060e8a89ee13fadb4a970d112fe589c284ab5dfe..e29a2b0f15a97024f77f0e4890645ef09d87e44f 100644 --- a/typo3/sysext/extensionmanager/Classes/Command/ActivateExtensionCommand.php +++ b/typo3/sysext/extensionmanager/Classes/Command/ActivateExtensionCommand.php @@ -15,15 +15,16 @@ namespace TYPO3\CMS\Extensionmanager\Command; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use TYPO3\CMS\Core\Core\Bootstrap; +use TYPO3\CMS\Core\Package\Event\PackagesMayHaveChangedEvent; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; -use TYPO3\CMS\Extbase\SignalSlot\Dispatcher; use TYPO3\CMS\Extensionmanager\Utility\InstallUtility; /** @@ -61,9 +62,9 @@ class ActivateExtensionCommand extends Command Bootstrap::initializeBackendAuthentication(); $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + // Emits packages may have changed signal - $signalSlotDispatcher = $objectManager->get(Dispatcher::class); - $signalSlotDispatcher->dispatch('PackageManagement', 'packagesMayHaveChanged'); + GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch(new PackagesMayHaveChangedEvent()); // Do the installation process $objectManager->get(InstallUtility::class)->install($extensionKey); diff --git a/typo3/sysext/extensionmanager/Classes/Compatibility/SlotReplacement.php b/typo3/sysext/extensionmanager/Classes/Compatibility/SlotReplacement.php new file mode 100644 index 0000000000000000000000000000000000000000..77c3533e59bad5641847442bb0f8d84005372d83 --- /dev/null +++ b/typo3/sysext/extensionmanager/Classes/Compatibility/SlotReplacement.php @@ -0,0 +1,134 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Extensionmanager\Compatibility; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent; +use TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent; +use TYPO3\CMS\Core\Package\Event\BeforePackageActivationEvent; +use TYPO3\CMS\Extbase\SignalSlot\Dispatcher as SignalSlotDispatcher; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionDatabaseContentHasBeenImportedEvent; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionFilesHaveBeenImportedEvent; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionStaticDatabaseContentHasBeenImportedEvent; +use TYPO3\CMS\Extensionmanager\Event\AvailableActionsForExtensionEvent; +use TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService; +use TYPO3\CMS\Extensionmanager\Utility\InstallUtility; +use TYPO3\CMS\Extensionmanager\ViewHelpers\ProcessAvailableActionsViewHelper; + +/** + * This class provides a replacement for all existing signals in EXT:extensionmanager of TYPO3 Core, which now act as a + * simple wrapper for PSR-14 events with a simple ("first prioritized") listener implementation. + * + * @internal Please note that this class will likely be removed in TYPO3 v11, and Extension Authors should + * switch to PSR-14 event listeners. + */ +class SlotReplacement +{ + /** + * @var SignalSlotDispatcher + */ + protected $signalSlotDispatcher; + + public function __construct(SignalSlotDispatcher $signalSlotDispatcher) + { + $this->signalSlotDispatcher = $signalSlotDispatcher; + } + + public function afterExtensionInstallSlot(AfterPackageActivationEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + InstallUtility::class, + 'afterExtensionInstall', + [ + $event->getPackageKey(), + $event->getEmitter() + ] + ); + } + + public function afterExtensionUninstallSlot(AfterPackageDeactivationEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + InstallUtility::class, + 'afterExtensionUninstall', + [ + $event->getPackageKey(), + $event->getEmitter() + ] + ); + } + + public function emitAfterExtensionT3DImportSignal(AfterExtensionDatabaseContentHasBeenImportedEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + InstallUtility::class, + 'afterExtensionT3DImport', + [ + $event->getImportFileName(), + $event->getImportResult(), + $event->getEmitter() + ] + ); + } + + public function emitAfterExtensionStaticSqlImportSignal(AfterExtensionStaticDatabaseContentHasBeenImportedEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + InstallUtility::class, + 'afterExtensionStaticSqlImport', + [ + $event->getSqlFileName(), + $event->getEmitter() + ] + ); + } + + public function emitAfterExtensionFileImportSignal(AfterExtensionFilesHaveBeenImportedEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + InstallUtility::class, + 'afterExtensionFileImport', + [ + $event->getDestinationAbsolutePath(), + $event->getEmitter() + ] + ); + } + + public function emitWillInstallExtensionsSignal(BeforePackageActivationEvent $event): void + { + $this->signalSlotDispatcher->dispatch( + ExtensionManagementService::class, + 'willInstallExtensions', + [ + $event->getPackageKeys() + ] + ); + } + + public function emitProcessActionsSignal(AvailableActionsForExtensionEvent $event): void + { + $actions = $event->getActions(); + $this->signalSlotDispatcher->dispatch( + ProcessAvailableActionsViewHelper::class, + 'processActions', + [ + $event->getPackageData(), + &$actions, + ] + ); + $event->setActions($actions); + } +} diff --git a/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionDatabaseContentHasBeenImportedEvent.php b/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionDatabaseContentHasBeenImportedEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..4c7a6d323d0784be68cd2bdcd67f02a4ce775630 --- /dev/null +++ b/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionDatabaseContentHasBeenImportedEvent.php @@ -0,0 +1,72 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Extensionmanager\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\Extensionmanager\Utility\InstallUtility; + +/** + * Event that is triggered after a package has imported the database file shipped within a t3d/xml import file + */ +final class AfterExtensionDatabaseContentHasBeenImportedEvent +{ + /** + * @var string + */ + private $packageKey; + + /** + * @var string + */ + private $importFileName; + + /** + * @var int + */ + private $importResult; + + /** + * @var InstallUtility + */ + private $emitter; + + public function __construct(string $packageKey, string $importFileName, int $importResult, InstallUtility $emitter) + { + $this->packageKey = $packageKey; + $this->importFileName = $importFileName; + $this->importResult = $importResult; + $this->emitter = $emitter; + } + + public function getPackageKey(): string + { + return $this->packageKey; + } + + public function getImportFileName(): string + { + return $this->importFileName; + } + + public function getImportResult(): int + { + return $this->importResult; + } + + public function getEmitter(): InstallUtility + { + return $this->emitter; + } +} diff --git a/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionFilesHaveBeenImportedEvent.php b/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionFilesHaveBeenImportedEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..d6b0ca85ce6b14f11697b15f4269695f381cf412 --- /dev/null +++ b/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionFilesHaveBeenImportedEvent.php @@ -0,0 +1,61 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Extensionmanager\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\Extensionmanager\Utility\InstallUtility; + +/** + * Event that is triggered after a package has imported all extension files (from Initialisation/Files) + */ +final class AfterExtensionFilesHaveBeenImportedEvent +{ + /** + * @var string + */ + private $packageKey; + + /** + * @var string + */ + private $destinationAbsolutePath; + + /** + * @var InstallUtility + */ + private $emitter; + + public function __construct(string $packageKey, string $destinationAbsolutePath, InstallUtility $emitter) + { + $this->packageKey = $packageKey; + $this->destinationAbsolutePath = $destinationAbsolutePath; + $this->emitter = $emitter; + } + + public function getPackageKey(): string + { + return $this->packageKey; + } + + public function getDestinationAbsolutePath(): string + { + return $this->destinationAbsolutePath; + } + + public function getEmitter(): InstallUtility + { + return $this->emitter; + } +} diff --git a/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionStaticDatabaseContentHasBeenImportedEvent.php b/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionStaticDatabaseContentHasBeenImportedEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..ad330e1c69d607e91dff6a39be0f3cc3016cc13a --- /dev/null +++ b/typo3/sysext/extensionmanager/Classes/Event/AfterExtensionStaticDatabaseContentHasBeenImportedEvent.php @@ -0,0 +1,61 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Extensionmanager\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\Extensionmanager\Utility\InstallUtility; + +/** + * Event that is triggered after a package has imported the database file shipped within "ext_tables_static+adt.sql" + */ +final class AfterExtensionStaticDatabaseContentHasBeenImportedEvent +{ + /** + * @var string + */ + private $packageKey; + + /** + * @var string + */ + private $sqlFileName; + + /** + * @var InstallUtility + */ + private $emitter; + + public function __construct(string $packageKey, string $sqlFileName, InstallUtility $emitter) + { + $this->packageKey = $packageKey; + $this->sqlFileName = $sqlFileName; + $this->emitter = $emitter; + } + + public function getPackageKey(): string + { + return $this->packageKey; + } + + public function getSqlFileName(): string + { + return $this->sqlFileName; + } + + public function getEmitter(): InstallUtility + { + return $this->emitter; + } +} diff --git a/typo3/sysext/extensionmanager/Classes/Event/AvailableActionsForExtensionEvent.php b/typo3/sysext/extensionmanager/Classes/Event/AvailableActionsForExtensionEvent.php new file mode 100644 index 0000000000000000000000000000000000000000..ec288cece65c282c4308d282043105a966df5d93 --- /dev/null +++ b/typo3/sysext/extensionmanager/Classes/Event/AvailableActionsForExtensionEvent.php @@ -0,0 +1,69 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Extensionmanager\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 that is triggered when rendering an additional action (currently within a Fluid ViewHelper). + */ +final class AvailableActionsForExtensionEvent +{ + /** + * @var string + */ + private $packageKey; + + /** + * @var array + */ + private $packageData; + + /** + * @var string[] + */ + private $actions; + + public function __construct(string $packageKey, array $packageData, array $actions) + { + $this->packageKey = $packageKey; + $this->packageData = $packageData; + $this->actions = $actions; + } + + public function getPackageKey(): string + { + return $this->packageKey; + } + + public function getPackageData(): array + { + return $this->packageData; + } + + public function getActions(): array + { + return $this->actions; + } + + public function addAction(string $actionKey, string $content): void + { + $this->actions[$actionKey] = $content; + } + + public function setActions(array $actions): void + { + $this->actions = $actions; + } +} diff --git a/typo3/sysext/extensionmanager/Classes/Service/ExtensionManagementService.php b/typo3/sysext/extensionmanager/Classes/Service/ExtensionManagementService.php index 8215ca07ab6bf2049aa301e741f636ff3a82e0f5..c1e1f34745fd519813648a78857e1862439d53dd 100644 --- a/typo3/sysext/extensionmanager/Classes/Service/ExtensionManagementService.php +++ b/typo3/sysext/extensionmanager/Classes/Service/ExtensionManagementService.php @@ -14,10 +14,10 @@ namespace TYPO3\CMS\Extensionmanager\Service; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; +use TYPO3\CMS\Core\Package\Event\BeforePackageActivationEvent; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Extbase\Object\ObjectManager; -use TYPO3\CMS\Extbase\SignalSlot\Dispatcher; use TYPO3\CMS\Extensionmanager\Domain\Model\DownloadQueue; use TYPO3\CMS\Extensionmanager\Domain\Model\Extension; use TYPO3\CMS\Extensionmanager\Utility\DependencyUtility; @@ -65,6 +65,16 @@ class ExtensionManagementService implements SingletonInterface */ protected $skipDependencyCheck = false; + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + + public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + } + /** * @param DownloadQueue $downloadQueue */ @@ -369,7 +379,7 @@ class ExtensionManagementService implements SingletonInterface if (empty($installQueue)) { return []; } - $this->emitWillInstallExtensionsSignal($installQueue); + $this->eventDispatcher->dispatch(new BeforePackageActivationEvent($installQueue)); $resolvedDependencies = []; $this->installUtility->install(...array_keys($installQueue)); foreach ($installQueue as $extensionKey => $_) { @@ -432,26 +442,4 @@ class ExtensionManagementService implements SingletonInterface $this->downloadUtility->download($extension); } } - - /** - * @param array $installQueue - */ - protected function emitWillInstallExtensionsSignal(array $installQueue) - { - $this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'willInstallExtensions', [$installQueue]); - } - - /** - * Get the SignalSlot dispatcher - * - * @return Dispatcher - */ - protected function getSignalSlotDispatcher() - { - if (!isset($this->signalSlotDispatcher)) { - $this->signalSlotDispatcher = GeneralUtility::makeInstance(ObjectManager::class) - ->get(Dispatcher::class); - } - return $this->signalSlotDispatcher; - } } diff --git a/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php index 878f006f4a161aaf38c2f03ccf55d6b74c96e03f..8d0e00fae76eb98ebfb41d28cd4b55d308162c6e 100644 --- a/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php +++ b/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php @@ -15,6 +15,7 @@ namespace TYPO3\CMS\Extensionmanager\Utility; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; use Symfony\Component\Finder\Finder; @@ -24,13 +25,17 @@ use TYPO3\CMS\Core\Core\Bootstrap; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Database\Schema\SchemaMigrator; use TYPO3\CMS\Core\Database\Schema\SqlReader; +use TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent; +use TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent; use TYPO3\CMS\Core\Service\OpcodeCacheService; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Extbase\SignalSlot\Dispatcher; use TYPO3\CMS\Extensionmanager\Domain\Model\Extension; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionDatabaseContentHasBeenImportedEvent; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionFilesHaveBeenImportedEvent; +use TYPO3\CMS\Extensionmanager\Event\AfterExtensionStaticDatabaseContentHasBeenImportedEvent; use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException; use TYPO3\CMS\Impexp\Import; use TYPO3\CMS\Impexp\Utility\ImportExportUtility; @@ -74,14 +79,19 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface protected $cacheManager; /** - * @var Dispatcher + * @var \TYPO3\CMS\Core\Registry */ - protected $signalSlotDispatcher; + protected $registry; /** - * @var \TYPO3\CMS\Core\Registry + * @var EventDispatcherInterface */ - protected $registry; + protected $eventDispatcher; + + public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + } /** * @param \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility @@ -131,14 +141,6 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface $this->cacheManager = $cacheManager; } - /** - * @param Dispatcher $signalSlotDispatcher - */ - public function injectSignalSlotDispatcher(Dispatcher $signalSlotDispatcher) - { - $this->signalSlotDispatcher = $signalSlotDispatcher; - } - /** * @param \TYPO3\CMS\Core\Registry $registry */ @@ -176,7 +178,7 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface foreach ($extensionKeys as $extensionKey) { $this->processExtensionSetup($extensionKey); - $this->emitAfterExtensionInstallSignal($extensionKey); + $this->eventDispatcher->dispatch(new AfterPackageActivationEvent($extensionKey, 'typo3-cms-extension', $this)); } } @@ -187,8 +189,8 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface { $extension = $this->enrichExtensionWithDetails($extensionKey, false); $this->importInitialFiles($extension['siteRelPath'] ?? '', $extensionKey); - $this->importStaticSqlFile($extension['siteRelPath']); - $import = $this->importT3DFile($extension['siteRelPath']); + $this->importStaticSqlFile($extensionKey, $extension['siteRelPath']); + $import = $this->importT3DFile($extensionKey, $extension['siteRelPath']); $this->importSiteConfiguration($extension['siteRelPath'], $import); } @@ -251,30 +253,10 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface protected function unloadExtension($extensionKey) { $this->packageManager->deactivatePackage($extensionKey); - $this->emitAfterExtensionUninstallSignal($extensionKey); + $this->eventDispatcher->dispatch(new AfterPackageDeactivationEvent($extensionKey, 'typo3-cms-extension', $this)); $this->cacheManager->flushCachesInGroup('system'); } - /** - * Emits a signal after an extension has been installed - * - * @param string $extensionKey - */ - protected function emitAfterExtensionInstallSignal($extensionKey) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionInstall', [$extensionKey, $this]); - } - - /** - * Emits a signal after an extension has been uninstalled - * - * @param string $extensionKey - */ - protected function emitAfterExtensionUninstallSignal($extensionKey) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionUninstall', [$extensionKey, $this]); - } - /** * Checks if an extension is available in the system * @@ -476,10 +458,11 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface * Uses the export import extension to import a T3D or XML file to PID 0 * Execution state is saved in the this->registry, so it only happens once * + * @param string $extensionKey * @param string $extensionSiteRelPath * @return Import|null */ - protected function importT3DFile($extensionSiteRelPath): ?Import + protected function importT3DFile($extensionKey, $extensionSiteRelPath): ?Import { $registryKeysToCheck = [ $extensionSiteRelPath . 'Initialisation/data.t3d', @@ -507,7 +490,7 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface try { $importResult = $importExportUtility->importT3DFile(Environment::getPublicPath() . '/' . $importFileToUse, 0); $this->registry->set('extensionDataImport', $extensionSiteRelPath . 'Initialisation/dataImported', 1); - $this->emitAfterExtensionT3DImportSignal($importFileToUse, $importResult); + $this->eventDispatcher->dispatch(new AfterExtensionDatabaseContentHasBeenImportedEvent($extensionKey, $importFileToUse, $importResult, $this)); return $importExportUtility->getImport(); } catch (\ErrorException $e) { $this->logger->warning($e->getMessage(), ['exception' => $e]); @@ -516,24 +499,14 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface return null; } - /** - * Emits a signal after a t3d file was imported - * - * @param string $importFileToUse - * @param int $importResult - */ - protected function emitAfterExtensionT3DImportSignal($importFileToUse, $importResult) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionT3DImport', [$importFileToUse, $importResult, $this]); - } - /** * Imports a static tables SQL File (ext_tables_static+adt) * Execution state is saved in the this->registry, so it only happens once * + * @param string $extensionKey * @param string $extensionSiteRelPath */ - protected function importStaticSqlFile($extensionSiteRelPath) + protected function importStaticSqlFile(string $extensionKey, $extensionSiteRelPath) { $extTablesStaticSqlRelFile = $extensionSiteRelPath . 'ext_tables_static+adt.sql'; if (!$this->registry->get('extensionDataImport', $extTablesStaticSqlRelFile)) { @@ -545,20 +518,10 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface $this->importStaticSql($extTablesStaticSqlContent); } $this->registry->set('extensionDataImport', $extTablesStaticSqlRelFile, $shortFileHash); - $this->emitAfterExtensionStaticSqlImportSignal($extTablesStaticSqlRelFile); + $this->eventDispatcher->dispatch(new AfterExtensionStaticDatabaseContentHasBeenImportedEvent($extensionKey, $extTablesStaticSqlRelFile, $this)); } } - /** - * Emits a signal after a static sql file was imported - * - * @param string $extTablesStaticSqlRelFile - */ - protected function emitAfterExtensionStaticSqlImportSignal($extTablesStaticSqlRelFile) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionStaticSqlImport', [$extTablesStaticSqlRelFile, $this]); - } - /** * Imports files from Initialisation/Files to fileadmin * via lowlevel copy directory method @@ -581,21 +544,11 @@ class InstallUtility implements SingletonInterface, LoggerAwareInterface } GeneralUtility::copyDirectory($importRelFolder, $destinationRelPath); $this->registry->set('extensionDataImport', $importRelFolder, 1); - $this->emitAfterExtensionFileImportSignal($destinationAbsolutePath); + $this->eventDispatcher->dispatch(new AfterExtensionFilesHaveBeenImportedEvent($extensionKey, $destinationAbsolutePath, $this)); } } } - /** - * Emits a signal after extension files were imported - * - * @param string $destinationAbsolutePath - */ - protected function emitAfterExtensionFileImportSignal($destinationAbsolutePath) - { - $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionFileImport', [$destinationAbsolutePath, $this]); - } - /** * @param string $extensionSiteRelPath * @param Import|null $import diff --git a/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php index f792dc136c2b7a8f27bd9c15769e4bfde3ad0db0..25bb403047687f6036c9adb395ecd57e45f58fa2 100644 --- a/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php +++ b/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php @@ -14,7 +14,9 @@ namespace TYPO3\CMS\Extensionmanager\Utility; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Core\Core\Environment; +use TYPO3\CMS\Core\Package\Event\PackagesMayHaveChangedEvent; use TYPO3\CMS\Core\Package\PackageInterface; use TYPO3\CMS\Core\Package\PackageManager; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; @@ -56,14 +58,19 @@ class ListUtility implements \TYPO3\CMS\Core\SingletonInterface protected $packageManager; /** - * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher + * @var array */ - protected $signalSlotDispatcher; + protected $availableExtensions; /** - * @var array + * @var EventDispatcherInterface */ - protected $availableExtensions; + protected $eventDispatcher; + + public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + } /** * @param EmConfUtility $emConfUtility @@ -97,14 +104,6 @@ class ListUtility implements \TYPO3\CMS\Core\SingletonInterface $this->packageManager = $packageManager; } - /** - * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher - */ - public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher) - { - $this->signalSlotDispatcher = $signalSlotDispatcher; - } - /** * Returns the list of available, but not necessarily loaded extensions * @@ -114,7 +113,7 @@ class ListUtility implements \TYPO3\CMS\Core\SingletonInterface { if ($this->availableExtensions === null) { $this->availableExtensions = []; - $this->emitPackagesMayHaveChangedSignal(); + $this->eventDispatcher->dispatch(new PackagesMayHaveChangedEvent()); foreach ($this->packageManager->getAvailablePackages() as $package) { $this->availableExtensions[$package->getPackageKey()] = [ 'packagePath' => $package->getPackagePath(), @@ -149,14 +148,6 @@ class ListUtility implements \TYPO3\CMS\Core\SingletonInterface return $this->packageManager->getPackage($extensionKey); } - /** - * Emits packages may have changed signal - */ - protected function emitPackagesMayHaveChangedSignal() - { - $this->signalSlotDispatcher->dispatch('PackageManagement', 'packagesMayHaveChanged'); - } - /** * Returns "System", "Global" or "Local" based on extension position in filesystem. * diff --git a/typo3/sysext/extensionmanager/Classes/ViewHelpers/ProcessAvailableActionsViewHelper.php b/typo3/sysext/extensionmanager/Classes/ViewHelpers/ProcessAvailableActionsViewHelper.php index fa86fffe8df8fd7f4bc8ab5a726c13d0b30a581e..91cfc5fdd92a1314509e24309437fe324af956ae 100644 --- a/typo3/sysext/extensionmanager/Classes/ViewHelpers/ProcessAvailableActionsViewHelper.php +++ b/typo3/sysext/extensionmanager/Classes/ViewHelpers/ProcessAvailableActionsViewHelper.php @@ -14,6 +14,8 @@ namespace TYPO3\CMS\Extensionmanager\ViewHelpers; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; +use TYPO3\CMS\Extensionmanager\Event\AvailableActionsForExtensionEvent; use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper; /** @@ -23,28 +25,20 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper; */ class ProcessAvailableActionsViewHelper extends AbstractTagBasedViewHelper { - const SIGNAL_ProcessActions = 'processActions'; - /** - * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher + * @var EventDispatcherInterface */ - protected $signalSlotDispatcher; + protected $eventDispatcher; - /** - * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher - */ - public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher) + public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher) { - $this->signalSlotDispatcher = $signalSlotDispatcher; + $this->eventDispatcher = $eventDispatcher; } - /** - * Initialize arguments - */ public function initializeArguments() { parent::initializeArguments(); - $this->registerArgument('extension', 'string', '', true); + $this->registerArgument('extension', 'array', '', true); } /** @@ -54,32 +48,11 @@ class ProcessAvailableActionsViewHelper extends AbstractTagBasedViewHelper */ public function render() { - $extension = $this->arguments['extension']; $html = $this->renderChildren(); $actions = preg_split('#\\n\\s*#s', trim($html)); - $actions = $this->emitProcessActionsSignal($extension, $actions); - - return implode(' ', $actions); - } - - /** - * Emits a signal after the list of actions is processed - * - * @param string $extension - * @param array $actions - * @return array Modified action array - */ - protected function emitProcessActionsSignal($extension, array $actions) - { - $this->signalSlotDispatcher->dispatch( - __CLASS__, - static::SIGNAL_ProcessActions, - [ - $extension, - &$actions, - ] - ); - return $actions; + $event = new AvailableActionsForExtensionEvent($this->arguments['extension']['key'], $this->arguments['extension'], $actions); + $this->eventDispatcher->dispatch($event); + return implode(' ', $event->getActions()); } } diff --git a/typo3/sysext/extensionmanager/Configuration/Services.yaml b/typo3/sysext/extensionmanager/Configuration/Services.yaml index d944395064a3598409f67eb9400606443aec32ad..c94629a9cd35463e0a79a7084e08d87611eb5cd7 100644 --- a/typo3/sysext/extensionmanager/Configuration/Services.yaml +++ b/typo3/sysext/extensionmanager/Configuration/Services.yaml @@ -9,3 +9,34 @@ services: # Tasks require EXT:scheduler, reports require # EXT:reports to be installed, ignore for now. exclude: '../Classes/{Task,Report}' + + TYPO3\CMS\Extensionmanager\Compatibility\SlotReplacement: + tags: + - name: event.listener + identifier: 'legacy-slot' + method: 'emitWillInstallExtensionsSignal' + event: TYPO3\CMS\Core\Package\Event\BeforePackageActivationEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'afterExtensionInstallSlot' + event: TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'afterExtensionUninstallSlot' + event: TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitAfterExtensionT3DImportSignal' + event: TYPO3\CMS\Extensionmanager\Event\AfterExtensionDatabaseContentHasBeenImportedEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitAfterExtensionStaticSqlImportSignal' + event: TYPO3\CMS\Extensionmanager\Event\AfterExtensionStaticDatabaseContentHasBeenImportedEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitAfterExtensionFileImportSignal' + event: TYPO3\CMS\Extensionmanager\Event\AfterExtensionFilesHaveBeenImportedEvent + - name: event.listener + identifier: 'legacy-slot' + method: 'emitProcessActionsSignal' + event: TYPO3\CMS\Extensionmanager\Event\AvailableActionsForExtensionEvent diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Report/ExtensionStatusTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Report/ExtensionStatusTest.php index e630c14f46679745563c3d0125d4aac349289111..85f7ef0cf5d8b06b630a68c734239ea317b825fe 100644 --- a/typo3/sysext/extensionmanager/Tests/Unit/Report/ExtensionStatusTest.php +++ b/typo3/sysext/extensionmanager/Tests/Unit/Report/ExtensionStatusTest.php @@ -17,6 +17,7 @@ namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Report; */ use Prophecy\Argument; +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Core\Localization\LanguageService; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; @@ -273,8 +274,10 @@ class ExtensionStatusTest extends UnitTestCase 'terObject' => $mockTerObject, ], ]; + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class)->reveal(); /** @var $mockListUtility ListUtility|\PHPUnit\Framework\MockObject\MockObject */ $mockListUtility = $this->getMockBuilder(ListUtility::class)->getMock(); + $mockListUtility->injectEventDispatcher($eventDispatcher); $mockListUtility ->expects(self::once()) ->method('getAvailableAndInstalledExtensionsWithAdditionalInformation') diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Service/ExtensionManagementServiceTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Service/ExtensionManagementServiceTest.php index 8263cb9c0191625a39c077ae9a70f4af68c942c7..ccedf15771e62065ede1f0b6d21db4e5d47968d8 100644 --- a/typo3/sysext/extensionmanager/Tests/Unit/Service/ExtensionManagementServiceTest.php +++ b/typo3/sysext/extensionmanager/Tests/Unit/Service/ExtensionManagementServiceTest.php @@ -16,9 +16,7 @@ namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Service; */ use Prophecy\Argument; -use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Extbase\Object\ObjectManager; -use TYPO3\CMS\Extbase\SignalSlot\Dispatcher; +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Extensionmanager\Domain\Model\DownloadQueue; use TYPO3\CMS\Extensionmanager\Domain\Model\Extension; use TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService; @@ -45,9 +43,7 @@ class ExtensionManagementServiceTest extends UnitTestCase parent::setUp(); $this->resetSingletonInstances = true; $this->managementService = new ExtensionManagementService(); - $objectManager = $this->prophesize(ObjectManager::class); - $objectManager->get(Dispatcher::class)->willReturn($this->prophesize(Dispatcher::class)->reveal()); - GeneralUtility::setSingletonInstance(ObjectManager::class, $objectManager->reveal()); + $this->managementService->injectEventDispatcher($this->prophesize(EventDispatcherInterface::class)->reveal()); $this->downloadUtilityProphecy = $this->prophesize(DownloadUtility::class); $this->dependencyUtilityProphecy = $this->prophesize(DependencyUtility::class); diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Utility/DependencyUtilityTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Utility/DependencyUtilityTest.php index 5ac285ac31e31e0adebd72726c0bd7f184eb52b0..d00d2fef8022493232b90b221e6ba3f7ef066b9f 100644 --- a/typo3/sysext/extensionmanager/Tests/Unit/Utility/DependencyUtilityTest.php +++ b/typo3/sysext/extensionmanager/Tests/Unit/Utility/DependencyUtilityTest.php @@ -14,11 +14,13 @@ namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Utility; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Extensionmanager\Domain\Model\Dependency; use TYPO3\CMS\Extensionmanager\Domain\Model\Extension; use TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository; use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException; use TYPO3\CMS\Extensionmanager\Utility\DependencyUtility; +use TYPO3\CMS\Extensionmanager\Utility\ListUtility; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; /** @@ -311,9 +313,11 @@ class DependencyUtilityTest extends UnitTestCase 'foo' => [], 'bar' => [] ]; - $listUtilityMock = $this->getMockBuilder(\TYPO3\CMS\Extensionmanager\Utility\ListUtility::class) + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class)->reveal(); + $listUtilityMock = $this->getMockBuilder(ListUtility::class) ->setMethods(['getAvailableExtensions']) ->getMock(); + $listUtilityMock->injectEventDispatcher($eventDispatcher); $listUtilityMock->expects(self::atLeastOnce())->method('getAvailableExtensions')->willReturn($availableExtensions); $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']); $dependencyUtility->_set('listUtility', $listUtilityMock); @@ -331,9 +335,11 @@ class DependencyUtilityTest extends UnitTestCase 'foo' => [], 'bar' => [] ]; - $listUtilityMock = $this->getMockBuilder(\TYPO3\CMS\Extensionmanager\Utility\ListUtility::class) + $eventDispatcher = $this->prophesize(EventDispatcherInterface::class)->reveal(); + $listUtilityMock = $this->getMockBuilder(ListUtility::class) ->setMethods(['getAvailableExtensions']) ->getMock(); + $listUtilityMock->injectEventDispatcher($eventDispatcher); $listUtilityMock->expects(self::atLeastOnce())->method('getAvailableExtensions')->willReturn($availableExtensions); $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']); $dependencyUtility->_set('listUtility', $listUtilityMock); diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Utility/InstallUtilityTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Utility/InstallUtilityTest.php index 78d624d2189ca83dcb42f687d39d2b203fe27bc5..ec22ea10392f0fe6554efa6ac671a028597da9b1 100644 --- a/typo3/sysext/extensionmanager/Tests/Unit/Utility/InstallUtilityTest.php +++ b/typo3/sysext/extensionmanager/Tests/Unit/Utility/InstallUtilityTest.php @@ -16,6 +16,7 @@ namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Utility; */ use Prophecy\Argument; +use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Yaml\Yaml; use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\Frontend\NullFrontend; @@ -80,12 +81,9 @@ class InstallUtilityTest extends UnitTestCase 'getExtensionArray', 'enrichExtensionWithDetails', 'importInitialFiles', - 'emitAfterExtensionInstallSignal', - ], - [], - '', - false + ] ); + $this->installMock->injectEventDispatcher($this->prophesize(EventDispatcherInterface::class)->reveal()); $dependencyUtility = $this->getMockBuilder(DependencyUtility::class)->getMock(); $this->installMock->_set('dependencyUtility', $dependencyUtility); $this->installMock->expects(self::any()) @@ -284,7 +282,7 @@ class InstallUtilityTest extends UnitTestCase $installMock->_set('dependencyUtility', $dependencyUtility); $installMock->_set('registry', $registryMock); $installMock->expects(self::never())->method('getImportExportUtility'); - $installMock->_call('importT3DFile', $this->fakedExtensions[$extKey]['siteRelPath']); + $installMock->_call('importT3DFile', $extKey, $this->fakedExtensions[$extKey]['siteRelPath']); } /** @@ -301,7 +299,9 @@ class InstallUtilityTest extends UnitTestCase file_put_contents($absPath . 'Initialisation/Site/' . $siteIdentifier . '/config.yaml', $config); $subject = new InstallUtility(); + $subject->injectEventDispatcher($this->prophesize(EventDispatcherInterface::class)->reveal()); $listUtility = $this->prophesize(ListUtility::class); + $listUtility->injectEventDispatcher($this->prophesize(EventDispatcherInterface::class)->reveal()); $subject->injectListUtility($listUtility->reveal()); $availableExtensions = [ @@ -365,7 +365,9 @@ class InstallUtilityTest extends UnitTestCase file_put_contents($configDir . '/' . $existingSiteConfig, $config); $subject = new InstallUtility(); + $subject->injectEventDispatcher($this->prophesize(EventDispatcherInterface::class)->reveal()); $listUtility = $this->prophesize(ListUtility::class); + $listUtility->injectEventDispatcher($this->prophesize(EventDispatcherInterface::class)->reveal()); $subject->injectListUtility($listUtility->reveal()); $availableExtensions = [ diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Utility/ListUtilityTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Utility/ListUtilityTest.php index a1e138c8d2a4e6574802d05fcedf3b5e2e3c4040..f31ab30e43cedef1ddb23f1f335fa38e6284fe19 100644 --- a/typo3/sysext/extensionmanager/Tests/Unit/Utility/ListUtilityTest.php +++ b/typo3/sysext/extensionmanager/Tests/Unit/Utility/ListUtilityTest.php @@ -15,6 +15,7 @@ namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Utility; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Core\Package\Package; use TYPO3\CMS\Core\Package\PackageManager; use TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository; @@ -35,9 +36,8 @@ class ListUtilityTest extends UnitTestCase protected function setUp(): void { parent::setUp(); - $this->subject = $this->getMockBuilder(ListUtility::class) - ->setMethods(['emitPackagesMayHaveChangedSignal']) - ->getMock(); + $this->subject = new ListUtility(); + $this->subject->injectEventDispatcher($this->prophesize(EventDispatcherInterface::class)->reveal()); $packageManagerMock = $this->getMockBuilder(PackageManager::class) ->disableOriginalConstructor() ->getMock(); diff --git a/typo3/sysext/extensionmanager/ext_localconf.php b/typo3/sysext/extensionmanager/ext_localconf.php index a3a7d51585b4f1a89f4f46c83dcbf391d12f8aba..f6863dcf5bd46a631a967aede784d926fb86beac 100644 --- a/typo3/sysext/extensionmanager/ext_localconf.php +++ b/typo3/sysext/extensionmanager/ext_localconf.php @@ -2,10 +2,9 @@ defined('TYPO3_MODE') or die(); // Register extension list update task -$offlineMode = (bool)\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( +if (!(bool)\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( \TYPO3\CMS\Core\Configuration\ExtensionConfiguration::class -)->get('extensionmanager', 'offlineMode'); -if (!$offlineMode) { +)->get('extensionmanager', 'offlineMode')) { $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Extensionmanager\Task\UpdateExtensionListTask::class] = [ 'extension' => 'extensionmanager', 'title' => 'LLL:EXT:extensionmanager/Resources/Private/Language/locallang.xlf:task.updateExtensionListTask.name', @@ -13,18 +12,6 @@ if (!$offlineMode) { 'additionalFields' => '', ]; } -unset($offlineMode); - -if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_BE) { - $signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class); - $signalSlotDispatcher->connect( - \TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService::class, - 'willInstallExtensions', - \TYPO3\CMS\Core\Package\PackageManager::class, - 'scanAvailablePackages' - ); - unset($signalSlotDispatcher); -} // Register extension status report system $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['reports']['tx_reports']['status']['providers']['Extension Manager'][] =