diff --git a/typo3/sysext/backend/Configuration/Commands.php b/typo3/sysext/backend/Configuration/Commands.php deleted file mode 100644 index 7a7a9420e93b1447c131c2b694bf753c4d052170..0000000000000000000000000000000000000000 --- a/typo3/sysext/backend/Configuration/Commands.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php -/** - * Commands to be executed by typo3, where the key of the array - * is the name of the command (to be called as the first argument after typo3). - * Required parameter is the "class" of the command which needs to be a subclass - * of Symfony/Console/Command. - * - * example: bin/typo3 backend:lock - */ -return [ - 'backend:lock' => [ - 'class' => \TYPO3\CMS\Backend\Command\LockBackendCommand::class - ], - 'backend:unlock' => [ - 'class' => \TYPO3\CMS\Backend\Command\UnlockBackendCommand::class - ], - 'referenceindex:update' => [ - 'class' => \TYPO3\CMS\Backend\Command\ReferenceIndexUpdateCommand::class - ] -]; diff --git a/typo3/sysext/backend/Configuration/Services.yaml b/typo3/sysext/backend/Configuration/Services.yaml index 3dd9134617582151ac8c1cf65946d3159da61fe1..14d7049a180516d70a3beafa2e400dbe7f82cf18 100644 --- a/typo3/sysext/backend/Configuration/Services.yaml +++ b/typo3/sysext/backend/Configuration/Services.yaml @@ -7,6 +7,18 @@ services: TYPO3\CMS\Backend\: resource: '../Classes/*' + TYPO3\CMS\Backend\Command\LockBackendCommand: + tags: + - { name: 'console.command', command: 'backend:lock' } + + TYPO3\CMS\Backend\Command\UnlockBackendCommand: + tags: + - { name: 'console.command', command: 'backend:unlock' } + + TYPO3\CMS\Backend\Command\ReferenceIndexUpdateCommand: + tags: + - { name: 'console.command', command: 'referenceindex:update' } + # Temporary workaround until testing framework loads EXT:fluid in functional tests # @todo: Fix typo3/testing-framework and remove this TYPO3\CMS\Backend\View\BackendTemplateView: diff --git a/typo3/sysext/core/Classes/Command/SiteListCommand.php b/typo3/sysext/core/Classes/Command/SiteListCommand.php index c0a51d4156e0f280429bb7c4efc1152c87277908..c2fd02ea21b87d6cdf9491910e5e6435525d2c82 100644 --- a/typo3/sysext/core/Classes/Command/SiteListCommand.php +++ b/typo3/sysext/core/Classes/Command/SiteListCommand.php @@ -28,6 +28,17 @@ use TYPO3\CMS\Core\Site\SiteFinder; */ class SiteListCommand extends Command { + /** + * @var SiteFinder + */ + protected $siteFinder; + + public function __construct(SiteFinder $siteFinder) + { + $this->siteFinder = $siteFinder; + parent::__construct(); + } + /** * Defines the allowed options for this command */ @@ -44,8 +55,7 @@ class SiteListCommand extends Command protected function execute(InputInterface $input, OutputInterface $output) { $io = new SymfonyStyle($input, $output); - $siteFinder = new SiteFinder(); - $sites = $siteFinder->getAllSites(); + $sites = $this->siteFinder->getAllSites(); if (empty($sites)) { $io->title('No sites configured'); diff --git a/typo3/sysext/core/Classes/Console/CommandApplication.php b/typo3/sysext/core/Classes/Console/CommandApplication.php index 3492572060ba3929aaa9ca44371bfdab0b0f5f9c..8b8a86c0dcb1343abc59a51ba7e2d48500d859f7 100644 --- a/typo3/sysext/core/Classes/Console/CommandApplication.php +++ b/typo3/sysext/core/Classes/Console/CommandApplication.php @@ -29,7 +29,6 @@ use TYPO3\CMS\Core\Core\Bootstrap; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Localization\LanguageService; -use TYPO3\CMS\Core\Utility\GeneralUtility; /** * Entry point for the TYPO3 Command Line for Commands @@ -42,15 +41,21 @@ class CommandApplication implements ApplicationInterface */ protected $context; + /** + * @var CommandRegistry + */ + protected $commandRegistry; + /** * Instance of the symfony application * @var Application */ protected $application; - public function __construct(Context $context) + public function __construct(Context $context, CommandRegistry $commandRegistry) { $this->context = $context; + $this->commandRegistry = $commandRegistry; $this->checkEnvironmentOrDie(); $this->application = new Application('TYPO3 CMS', sprintf( '%s (Application Context: <comment>%s</comment>)', @@ -58,6 +63,7 @@ class CommandApplication implements ApplicationInterface Environment::getContext() )); $this->application->setAutoExit(false); + $this->application->setCommandLoader($commandRegistry); } /** @@ -113,11 +119,12 @@ class CommandApplication implements ApplicationInterface /** * Put all available commands inside the application + * + * Note: This method will be removed in TYPO3 v11 when support for Configuration/Commands.php is dropped. */ protected function populateAvailableCommands(): void { - $commands = GeneralUtility::makeInstance(CommandRegistry::class); - foreach ($commands as $commandName => $command) { + foreach ($this->commandRegistry->getLegacyCommands() as $commandName => $command) { /** @var Command $command */ $this->application->add($command); } diff --git a/typo3/sysext/core/Classes/Console/CommandRegistry.php b/typo3/sysext/core/Classes/Console/CommandRegistry.php index ff60a1561c8cd9431cf4cd873258e16f33a6c5c0..969a1be4f09ee9599d317d9206124a2dd94d9159 100644 --- a/typo3/sysext/core/Classes/Console/CommandRegistry.php +++ b/typo3/sysext/core/Classes/Console/CommandRegistry.php @@ -15,7 +15,10 @@ namespace TYPO3\CMS\Core\Console; * The TYPO3 project - inspiring people to share! */ +use Psr\Container\ContainerInterface; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\CommandLoader\CommandLoaderInterface; +use Symfony\Component\Console\Exception\CommandNotFoundException; use TYPO3\CMS\Core\Package\PackageManager; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -23,17 +26,22 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; /** * Registry for Symfony commands, populated from extensions */ -class CommandRegistry implements \IteratorAggregate, SingletonInterface +class CommandRegistry implements CommandLoaderInterface, \IteratorAggregate, SingletonInterface { /** * @var PackageManager */ protected $packageManager; + /** + * @var ContainerInterface + */ + protected $container; + /** * Map of commands * - * @var Command[] + * @var array */ protected $commands = []; @@ -44,21 +52,68 @@ class CommandRegistry implements \IteratorAggregate, SingletonInterface */ protected $commandConfigurations = []; + /** + * Map of lazy (DI-managed) command configurations with the command name as key + * + * @var array + */ + protected $lazyCommandConfigurations = []; + /** * @param PackageManager $packageManager + * @param ContainerInterface $container + */ + public function __construct(PackageManager $packageManager, ContainerInterface $container) + { + $this->packageManager = $packageManager; + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function has($name) + { + $this->populateCommandsFromPackages(); + + return array_key_exists($name, $this->commands); + } + + /** + * {@inheritdoc} */ - public function __construct(PackageManager $packageManager = null) + public function get($name) { - $this->packageManager = $packageManager ?: GeneralUtility::makeInstance(PackageManager::class); + try { + return $this->getCommandByIdentifier($name); + } catch (UnknownCommandException $e) { + throw new CommandNotFoundException($e->getMessage(), [], 1567969355, $e); + } + } + + /** + * {@inheritdoc} + */ + public function getNames() + { + $this->populateCommandsFromPackages(); + + return array_keys($this->commands); } /** * @return \Generator + * @deprecated will be removed in TYPO3 v11.0 when support for Configuration/Commands.php is dropped. */ public function getIterator(): \Generator { + trigger_error('Using ' . self::class . ' as iterable has been deprecated and will stop working in TYPO3 11.0.', E_USER_DEPRECATED); + $this->populateCommandsFromPackages(); foreach ($this->commands as $commandName => $command) { + if (is_string($command)) { + $command = $this->getInstance($command, $commandName); + } yield $commandName => $command; } } @@ -73,11 +128,30 @@ class CommandRegistry implements \IteratorAggregate, SingletonInterface $this->populateCommandsFromPackages(); foreach ($this->commands as $commandName => $command) { if ($this->commandConfigurations[$commandName]['schedulable'] ?? true) { + if (is_string($command)) { + $command = $this->getInstance($command, $commandName); + } yield $commandName => $command; } } } + /** + * @return \Generator + * @internal This method will be removed in TYPO3 v11 when support for Configuration/Commands.php is dropped. + */ + public function getLegacyCommands(): \Generator + { + $this->populateCommandsFromPackages(); + foreach ($this->commands as $commandName => $command) { + // Type string indicates lazy loading + if (is_string($command)) { + continue; + } + yield $commandName => $command; + } + } + /** * @param string $identifier * @throws CommandNameAlreadyInUseException @@ -95,7 +169,12 @@ class CommandRegistry implements \IteratorAggregate, SingletonInterface ); } - return $this->commands[$identifier] ?? null; + $command = $this->commands[$identifier] ?? null; + if (is_string($command)) { + $command = $this->getInstance($command, $identifier); + } + + return $command; } /** @@ -118,6 +197,13 @@ class CommandRegistry implements \IteratorAggregate, SingletonInterface if ($this->commands) { return; } + + foreach ($this->lazyCommandConfigurations as $commandName => $commandConfig) { + // Lazy commands shall be loaded from the Container on demand, store the command as string to indicate lazy loading + $this->commands[$commandName] = $commandConfig['class']; + $this->commandConfigurations[$commandName] = $commandConfig; + } + foreach ($this->packageManager->getActivePackages() as $package) { $commandsOfExtension = $package->getPackagePath() . 'Configuration/Commands.php'; if (@is_file($commandsOfExtension)) { @@ -129,6 +215,14 @@ class CommandRegistry implements \IteratorAggregate, SingletonInterface $commands = require $commandsOfExtension; if (is_array($commands)) { foreach ($commands as $commandName => $commandConfig) { + if (array_key_exists($commandName, $this->lazyCommandConfigurations)) { + // Lazy (DI managed) commands override classic commands from Configuration/Commands.php + // Skip this case to allow extensions to provide commands via DI config and to allow + // TYPO3 v9 backwards compatibile confguration via Configuration/Commands.php. + // Note: Also the deprecation error is skipped on-demand as the extension has been + // adapted and the configuration will be ignored as of TYPO3 v11. + continue; + } if (array_key_exists($commandName, $this->commands)) { throw new CommandNameAlreadyInUseException( 'Command "' . $commandName . '" registered by "' . $package->getPackageKey() . '" is already in use', @@ -137,9 +231,38 @@ class CommandRegistry implements \IteratorAggregate, SingletonInterface } $this->commands[$commandName] = GeneralUtility::makeInstance($commandConfig['class'], $commandName); $this->commandConfigurations[$commandName] = $commandConfig; + + trigger_error( + 'Registering console commands in Configuration/Commands.php has been deprecated and will stop working in TYPO3 v11.0.', + E_USER_DEPRECATED + ); } } } } } + + protected function getInstance(string $class, string $commandName): Command + { + $command = $this->container->get($class); + + if ($command instanceof Command) { + $command->setName($commandName); + return $command; + } + + throw new \InvalidArgumentException('Registered console command class ' . get_class($command) . ' does not inherit from ' . Command::class, 1567966448); + } + + /** + * @internal + */ + public function addLazyCommand(string $commandName, string $serviceName, bool $alias = false, bool $schedulable = true): void + { + $this->lazyCommandConfigurations[$commandName] = [ + 'class' => $serviceName, + 'alias' => $alias, + 'schedulable' => $schedulable, + ]; + } } diff --git a/typo3/sysext/core/Classes/DependencyInjection/ConsoleCommandPass.php b/typo3/sysext/core/Classes/DependencyInjection/ConsoleCommandPass.php new file mode 100644 index 0000000000000000000000000000000000000000..f35cc5cd9d4cf3fe6f2b1289557ae8c886fd20c7 --- /dev/null +++ b/typo3/sysext/core/Classes/DependencyInjection/ConsoleCommandPass.php @@ -0,0 +1,67 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Core\DependencyInjection; + +/* + * 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 Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use TYPO3\CMS\Core\Console\CommandRegistry; + +/** + * @internal + */ +final class ConsoleCommandPass implements CompilerPassInterface +{ + /** + * @var string + */ + private $tagName; + + /** + * @param string $tagName + */ + public function __construct(string $tagName) + { + $this->tagName = $tagName; + } + + /** + * @param ContainerBuilder $container + */ + public function process(ContainerBuilder $container) + { + $commandRegistryDefinition = $container->findDefinition(CommandRegistry::class); + if (!$commandRegistryDefinition) { + return; + } + + $unorderedEventListeners = []; + foreach ($container->findTaggedServiceIds($this->tagName) as $serviceName => $tags) { + $container->findDefinition($serviceName)->setPublic(true); + foreach ($tags as $attributes) { + if (!isset($attributes['command'])) { + continue; + } + + $commandRegistryDefinition->addMethodCall('addLazyCommand', [ + $attributes['command'], + $serviceName, + (bool)($attributes['alias'] ?? false), + (bool)($attributes['schedulable'] ?? true) + ]); + } + } + } +} diff --git a/typo3/sysext/core/Classes/ServiceProvider.php b/typo3/sysext/core/Classes/ServiceProvider.php index 481067386562d3979f670c75ac4a3d7a53108daf..959b20feaa44dfbf1e5a37ffa8ea2a75471ed560 100644 --- a/typo3/sysext/core/Classes/ServiceProvider.php +++ b/typo3/sysext/core/Classes/ServiceProvider.php @@ -35,6 +35,7 @@ class ServiceProvider extends AbstractServiceProvider return [ Cache\CacheManager::class => [ static::class, 'getCacheManager' ], Console\CommandApplication::class => [ static::class, 'getConsoleCommandApplication' ], + Console\CommandRegistry::class => [ static::class, 'getConsoleCommandRegistry' ], Context\Context::class => [ static::class, 'getContext' ], EventDispatcher\EventDispatcher::class => [ static::class, 'getEventDispatcher' ], EventDispatcher\ListenerProvider::class => [ static::class, 'getEventListenerProvider' ], @@ -77,7 +78,15 @@ class ServiceProvider extends AbstractServiceProvider public static function getConsoleCommandApplication(ContainerInterface $container): Console\CommandApplication { - return new Console\CommandApplication($container->get(Context\Context::class)); + return new Console\CommandApplication( + $container->get(Context\Context::class), + $container->get(Console\CommandRegistry::class) + ); + } + + public static function getConsoleCommandRegistry(ContainerInterface $container): Console\CommandRegistry + { + return new Console\CommandRegistry($container->get(Package\PackageManager::class), $container); } public static function getEventDispatcher(ContainerInterface $container): EventDispatcher\EventDispatcher diff --git a/typo3/sysext/core/Configuration/Commands.php b/typo3/sysext/core/Configuration/Commands.php deleted file mode 100644 index 15028c8ccf4eab8feb5bc2717457f075096fb845..0000000000000000000000000000000000000000 --- a/typo3/sysext/core/Configuration/Commands.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -return [ - 'dumpautoload' => [ - 'class' => \TYPO3\CMS\Core\Command\DumpAutoloadCommand::class, - 'schedulable' => false, - ], - 'mailer:spool:send' => [ - 'class' => \TYPO3\CMS\Core\Command\SendEmailCommand::class, - ], - 'extension:list' => [ - 'class' => \TYPO3\CMS\Core\Command\ExtensionListCommand::class, - 'schedulable' => false - ], - 'site:list' => [ - 'class' => \TYPO3\CMS\Core\Command\SiteListCommand::class, - 'schedulable' => false - ], - 'site:show' => [ - 'class' => \TYPO3\CMS\Core\Command\SiteShowCommand::class, - 'schedulable' => false - ] -]; diff --git a/typo3/sysext/core/Configuration/Services.php b/typo3/sysext/core/Configuration/Services.php index dc3ef1b92d43de7af285b98e426b1a1811e1345c..0c5420a9d0921049bff470b05287d2ec98cb158d 100644 --- a/typo3/sysext/core/Configuration/Services.php +++ b/typo3/sysext/core/Configuration/Services.php @@ -21,5 +21,6 @@ return function (ContainerConfigurator $container, ContainerBuilder $containerBu $containerBuilder->addCompilerPass(new DependencyInjection\ListenerProviderPass('event.listener')); $containerBuilder->addCompilerPass(new DependencyInjection\PublicServicePass('typo3.middleware')); $containerBuilder->addCompilerPass(new DependencyInjection\PublicServicePass('typo3.request_handler')); + $containerBuilder->addCompilerPass(new DependencyInjection\ConsoleCommandPass('console.command')); $containerBuilder->addCompilerPass(new DependencyInjection\AutowireInjectMethodsPass()); }; diff --git a/typo3/sysext/core/Configuration/Services.yaml b/typo3/sysext/core/Configuration/Services.yaml index bd6e57342068d90f695b515e90e89d83c4b23cc5..5ac89f353670695b3d3ca657ac4d6183cee7b348 100644 --- a/typo3/sysext/core/Configuration/Services.yaml +++ b/typo3/sysext/core/Configuration/Services.yaml @@ -10,6 +10,48 @@ services: TYPO3\CMS\Core\DependencyInjection\EnvVarProcessor: tags: ['container.env_var_processor'] + TYPO3\CMS\Core\Command\DumpAutoloadCommand: + tags: + - name: 'console.command' + command: 'dumpautoload' + schedulable: false + - name: 'console.command' + command: 'extensionmanager:extension:dumpclassloadinginformation' + alias: true + schedulable: false + - name: 'console.command' + command: 'extension:dumpclassloadinginformation' + alias: true + schedulable: false + + TYPO3\CMS\Core\Command\ExtensionListCommand: + tags: + - name: 'console.command' + command: 'extension:list' + schedulable: false + + TYPO3\CMS\Core\Command\SendEmailCommand: + tags: + - name: 'console.command' + command: 'mailer:spool:send' + - name: 'console.command' + command: 'swiftmailer:spool:send' + alias: true + schedulable: false + + + TYPO3\CMS\Core\Command\SiteListCommand: + tags: + - name: 'console.command' + command: 'site:list' + schedulable: false + + TYPO3\CMS\Core\Command\SiteShowCommand: + tags: + - name: 'console.command' + command: 'site:show' + schedulable: false + TYPO3\CMS\Core\Configuration\SiteConfiguration: arguments: $configPath: "%env(TYPO3:configPath)%/sites" diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89139-ConsoleCommandsConfigurationMigratedToSymfonyServiceTags.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89139-ConsoleCommandsConfigurationMigratedToSymfonyServiceTags.rst new file mode 100644 index 0000000000000000000000000000000000000000..4e373e7d45d65f6d8088fb36e516370303c7eed3 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89139-ConsoleCommandsConfigurationMigratedToSymfonyServiceTags.rst @@ -0,0 +1,73 @@ +.. include:: ../../Includes.txt + +===================================================================================== +Deprecation: #89139 - Console Commands configuration migrated to Symfony service tags +===================================================================================== + +See :issue:`89139` + +Description +=========== + +The console command configuration file format :php:`Configuration/Commands.php` +has been deprecated in favor of the dependency injection service tag +`console.command`. The tag allows to configure dependency injection and +command registration in one single location. + + +Impact +====== + +Providing a command configuration in :php:`Configuration/Commands.php` will +trigger a deprecation warning when the respective commands have not already +been defined via dependency injection service tags. + +Extensions that provide both, the deprecated configuration file and service +tags, will not trigger a deprecation message in order to allow extensions to +support multiple TYPO3 major versions. + + +Affected Installations +====================== + +TYPO3 installations with custom extensions that configure symfony console commands +via :php:`Configuration/Commands.php` and have not been migrated to add symfony +service tags. + + +Migration +========= + +Add the `console.command` tag to command classes. Use the tag attribute `command` +to specify the command name. The optional tag attribute `schedulable` may be set +to false to exclude the command from the TYPO3 scheduler. + +.. code-block:: yaml + + services: + _defaults: + autowire: true + autoconfigure: true + public: false + + MyVendor\MyExt\Commands\FooCommand + tags: + - name: 'console.command', + command: 'my:command' + schedulable: false + +Command aliases are to be configured as separate tags. +The optonal tag attribute `alias` should be set to true for alias commands. + +.. code-block:: yaml + + MyVendor\MyExt\Commands\BarCommand + tags: + - name: 'console.command' + command: 'my:bar' } + - name: 'console.command' + command: 'my:old-bar-command' + alias: true + schedulable: false + +.. index:: CLI, PHP-API, PartiallyScanned, ext:core diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-89139-AddDependencyInjectionSupportForConsoleCommands.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-89139-AddDependencyInjectionSupportForConsoleCommands.rst new file mode 100644 index 0000000000000000000000000000000000000000..3a981cd0cf2bebca43aa932c1b93fb5274ec9afd --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-89139-AddDependencyInjectionSupportForConsoleCommands.rst @@ -0,0 +1,73 @@ +.. include:: ../../Includes.txt + +======================================================================= +Feature: #89139 - Add dependency injection support for console commands +======================================================================= + +See :issue:`89139` + +Description +=========== + +Support for dependency injection in console commands has been added. + +Command dependencies can now be injected via constructor or other injection techniques. +Therefore a new dependency injection tag `console.command` has been added. +Commands tagged with `console.command` are lazy loaded. That means they will only be +instantiated when they are actually executed, when the `help` subcommand is executed, +or when available schedulable commands are iterated. + +The legacy command definition format :php:`Confguration/Commands.php` has been deprecated. + + +Impact +====== + +It is recommended to configure dependency injection tags for all commands, as the legacy command +definition format :php:`Confguration/Commands.php` has been deprecated. + +Commands that have been configured via `console.command` tag override legacy commands from +:php:`Confguration/Commands.php` without throwing a deprecation error for those commands. +Backwards compatibility with older TYPO3 version can be achieved by specifying both variants, +legacy configuration in :php:`Confguration/Commands.php` and new configuration via +`console.command` tag. + + +Usage +===== + +Add the `console.command` tag to command classes. +Use the tag attribute `command` to specify the command name. +The optional tag attribute `schedulable` may be set to false +to exclude the command from the TYPO3 scheduler. + +.. code-block:: yaml + + services: + _defaults: + autowire: true + autoconfigure: true + public: false + + MyVendor\MyExt\Commands\FooCommand + tags: + - name: 'console.command' + command: 'my:command' + schedulable: false + +Command aliases are to be configured as separate tags. +The optonal tag attribute `alias` should be set to true for alias commands. + +.. code-block:: yaml + + MyVendor\MyExt\Commands\BarCommand + tags: + - name: 'console.command' + command: 'my:bar' + - name: 'console.command' + command: 'my:old-bar-command' + alias: true + schedulable: false + + +.. index:: CLI, PHP-API, ext:core diff --git a/typo3/sysext/core/Tests/Unit/Console/CommandRegistryTest.php b/typo3/sysext/core/Tests/Unit/Console/CommandRegistryTest.php index 0d57be61dcaf99b43a3dac35b8f48231fc0d2432..aa301cb9b658967a46331be3e4195a0e50a6a388 100644 --- a/typo3/sysext/core/Tests/Unit/Console/CommandRegistryTest.php +++ b/typo3/sysext/core/Tests/Unit/Console/CommandRegistryTest.php @@ -16,11 +16,10 @@ namespace TYPO3\CMS\Core\Tests\Unit\Console; */ use org\bovigo\vfs\vfsStream; -use Prophecy\Prophecy\ObjectProphecy; +use Psr\Container\ContainerInterface; use Symfony\Component\Console\Command\Command; -use TYPO3\CMS\Core\Console\CommandNameAlreadyInUseException; +use Symfony\Component\Console\CommandLoader\CommandLoaderInterface; use TYPO3\CMS\Core\Console\CommandRegistry; -use TYPO3\CMS\Core\Console\UnknownCommandException; use TYPO3\CMS\Core\Package\PackageInterface; use TYPO3\CMS\Core\Package\PackageManager; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; @@ -40,112 +39,97 @@ class CommandRegistryTest extends UnitTestCase */ protected $packageManagerProphecy; + /** + * @var ContainerInterface|\Prophecy\Prophecy\ObjectProphecy + */ + protected $containerProphecy; + /** * Set up this testcase */ protected function setUp(): void { parent::setUp(); - $commandMockClass = $this->getMockClass(Command::class, ['dummy']); - $this->rootDirectory = vfsStream::setup('root', null, [ - 'package1' => [ - 'Configuration' => [ - 'Commands.php' => '<?php return ["first:command" => [ "class" => "' . $commandMockClass . '" ]];', - ], - ], - 'package2' => [ - 'Configuration' => [ - 'Commands.php' => '<?php return ["second:command" => [ "class" => "' . $commandMockClass . '" ]];', - ], - ], - 'package3' => [ - 'Configuration' => [ - 'Commands.php' => '<?php return ["third:command" => [ "class" => "' . $commandMockClass . '" ]];', - ], - ], - 'package4' => [ - 'Configuration' => [ - 'Commands.php' => '<?php return ["third:command" => [ "class" => "' . $commandMockClass . '" ]];', - ], - ], - ]); /** @var PackageManager */ $this->packageManagerProphecy = $this->prophesize(PackageManager::class); + $this->packageManagerProphecy->getActivePackages()->willReturn([]); + + /** @var ContainerInterface */ + $this->containerProphecy = $this->prophesize(ContainerInterface::class); } /** * @test */ - public function iteratesCommandsOfActivePackages() + public function implementsCommandLoaderInterface() { - /** @var PackageInterface */ - $package1 = $this->prophesize(PackageInterface::class); - $package1->getPackagePath()->willReturn($this->rootDirectory->getChild('package1')->url() . '/'); - /** @var PackageInterface */ - $package2 = $this->prophesize(PackageInterface::class); - $package2->getPackagePath()->willReturn($this->rootDirectory->getChild('package2')->url() . '/'); - - $this->packageManagerProphecy->getActivePackages()->willReturn([$package1->reveal(), $package2->reveal()]); - - $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal()); - $commands = iterator_to_array($commandRegistry); - - self::assertCount(2, $commands); - self::assertContainsOnlyInstancesOf(Command::class, $commands); + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + self::assertInstanceof(CommandLoaderInterface::class, $commandRegistry); } /** * @test */ - public function throwsExceptionOnDuplicateCommand() + public function iteratesLazyCommandsOfActivePackages() { - /** @var PackageInterface */ - $package3 = $this->prophesize(PackageInterface::class); - $package3->getPackagePath()->willReturn($this->rootDirectory->getChild('package3')->url() . '/'); - /** @var PackageInterface */ - $package4 = $this->prophesize(PackageInterface::class); - $package4->getPackagePath()->willReturn($this->rootDirectory->getChild('package4')->url() . '/'); - $package4->getPackageKey()->willReturn('package4'); + $command1MockClass = $this->getMockClass(Command::class, ['dummy']); + $command2MockClass = $this->getMockClass(Command::class, ['dummy']); + + $this->containerProphecy->get('command1')->willReturn(new $command1MockClass); + $this->containerProphecy->get('command2')->willReturn(new $command2MockClass); - $this->packageManagerProphecy->getActivePackages()->willReturn([$package3->reveal(), $package4->reveal()]); + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + $commandRegistry->addLazyCommand('test:command', 'command1'); + $commandRegistry->addLazyCommand('test:command2', 'command2'); - $this->expectException(CommandNameAlreadyInUseException::class); - $this->expectExceptionCode(1484486383); + $commandNames = $commandRegistry->getNames(); - $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal()); - iterator_to_array($commandRegistry); + self::assertCount(2, $commandNames); + self::assertInstanceOf($command1MockClass, $commandRegistry->get('test:command')); + self::assertInstanceOf($command1MockClass, $commandRegistry->get('test:command2')); } /** * @test */ - public function getCommandByIdentifierReturnsRegisteredCommand() + public function iteratesLegacyCommandsOfActivePackages() { - /** @var PackageInterface|ObjectProphecy $package */ - $package = $this->prophesize(PackageInterface::class); - $package->getPackagePath()->willReturn($this->rootDirectory->getChild('package1')->url() . '/'); - $package->getPackageKey()->willReturn('package1'); + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + $commands = iterator_to_array($commandRegistry->getLegacyCommands()); - $this->packageManagerProphecy->getActivePackages()->willReturn([$package->reveal()]); - - $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal()); - $command = $commandRegistry->getCommandByIdentifier('first:command'); - - self::assertInstanceOf(Command::class, $command); + self::assertCount(0, $commands); + self::assertContainsOnlyInstancesOf(Command::class, $commands); } /** * @test */ - public function throwsUnknowCommandExceptionIfUnregisteredCommandIsRequested() + public function lazyCommandOverridesLegacyCommandsWithoutDeprecationError() { - $this->packageManagerProphecy->getActivePackages()->willReturn([]); + $commandMockClass = $this->getMockClass(Command::class, ['dummy']); + $this->rootDirectory = vfsStream::setup('root', null, [ + 'package1' => [ + 'Configuration' => [ + 'Commands.php' => '<?php return ["first:command" => [ "class" => "' . $commandMockClass . '" ]];', + ], + ], + ]); + /** @var PackageInterface */ + $package = $this->prophesize(PackageInterface::class); + $package->getPackagePath()->willReturn($this->rootDirectory->getChild('package1')->url() . '/'); + + $this->packageManagerProphecy->getActivePackages()->willReturn([$package->reveal()]); + + $this->containerProphecy->get($commandMockClass)->willReturn(new $commandMockClass); + + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + $commandRegistry->addLazyCommand('first:command', $commandMockClass); - $this->expectException(UnknownCommandException::class); - $this->expectExceptionCode(1510906768); + $nonLazyCommands = iterator_to_array($commandRegistry->getLegacyCommands()); + $lazyCommands = $commandRegistry->getNames(); - $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal()); - $commandRegistry->getCommandByIdentifier('foo'); + self::assertCount(0, $nonLazyCommands); + self::assertCount(1, $lazyCommands); } } diff --git a/typo3/sysext/core/Tests/UnitDeprecated/Console/CommandRegistryTest.php b/typo3/sysext/core/Tests/UnitDeprecated/Console/CommandRegistryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..777ea211d055dc74d2b769433a77a6e4cff5a095 --- /dev/null +++ b/typo3/sysext/core/Tests/UnitDeprecated/Console/CommandRegistryTest.php @@ -0,0 +1,181 @@ +<?php +declare(strict_types = 1); +namespace TYPO3\CMS\Core\Tests\UnitDeprecated\Console; + +/* + * 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 org\bovigo\vfs\vfsStream; +use Prophecy\Prophecy\ObjectProphecy; +use Psr\Container\ContainerInterface; +use Symfony\Component\Console\Command\Command; +use TYPO3\CMS\Core\Console\CommandNameAlreadyInUseException; +use TYPO3\CMS\Core\Console\CommandRegistry; +use TYPO3\CMS\Core\Console\UnknownCommandException; +use TYPO3\CMS\Core\Package\PackageInterface; +use TYPO3\CMS\Core\Package\PackageManager; +use TYPO3\TestingFramework\Core\Unit\UnitTestCase; + +/** + * Testcase for CommandRegistry + */ +class CommandRegistryTest extends UnitTestCase +{ + /** + * @var \org\bovigo\vfs\vfsStreamDirectory + */ + protected $rootDirectory; + + /** + * @var PackageManager|\Prophecy\Prophecy\ObjectProphecy + */ + protected $packageManagerProphecy; + + /** + * @var ContainerInterface|\Prophecy\Prophecy\ObjectProphecy + */ + protected $containerProphecy; + + /** + * Set up this testcase + */ + protected function setUp(): void + { + parent::setUp(); + $commandMockClass = $this->getMockClass(Command::class, ['dummy']); + $this->rootDirectory = vfsStream::setup('root', null, [ + 'package1' => [ + 'Configuration' => [ + 'Commands.php' => '<?php return ["first:command" => [ "class" => "' . $commandMockClass . '" ]];', + ], + ], + 'package2' => [ + 'Configuration' => [ + 'Commands.php' => '<?php return ["second:command" => [ "class" => "' . $commandMockClass . '" ]];', + ], + ], + 'package3' => [ + 'Configuration' => [ + 'Commands.php' => '<?php return ["third:command" => [ "class" => "' . $commandMockClass . '" ]];', + ], + ], + 'package4' => [ + 'Configuration' => [ + 'Commands.php' => '<?php return ["third:command" => [ "class" => "' . $commandMockClass . '" ]];', + ], + ], + ]); + + /** @var PackageManager */ + $this->packageManagerProphecy = $this->prophesize(PackageManager::class); + + /** @var ContainerInterface */ + $this->containerProphecy = $this->prophesize(ContainerInterface::class); + } + + /** + * @test + */ + public function iteratesCommandsOfActivePackages() + { + /** @var PackageInterface */ + $package1 = $this->prophesize(PackageInterface::class); + $package1->getPackagePath()->willReturn($this->rootDirectory->getChild('package1')->url() . '/'); + /** @var PackageInterface */ + $package2 = $this->prophesize(PackageInterface::class); + $package2->getPackagePath()->willReturn($this->rootDirectory->getChild('package2')->url() . '/'); + + $this->packageManagerProphecy->getActivePackages()->willReturn([$package1->reveal(), $package2->reveal()]); + + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + $commands = iterator_to_array($commandRegistry); + + self::assertCount(2, $commands); + self::assertContainsOnlyInstancesOf(Command::class, $commands); + } + + /** + * @test + */ + public function iteratesLegacyCommandsOfActivePackages() + { + /** @var PackageInterface */ + $package1 = $this->prophesize(PackageInterface::class); + $package1->getPackagePath()->willReturn($this->rootDirectory->getChild('package1')->url() . '/'); + /** @var PackageInterface */ + $package2 = $this->prophesize(PackageInterface::class); + $package2->getPackagePath()->willReturn($this->rootDirectory->getChild('package2')->url() . '/'); + + $this->packageManagerProphecy->getActivePackages()->willReturn([$package1->reveal(), $package2->reveal()]); + + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + $commands = iterator_to_array($commandRegistry->getLegacyCommands()); + + self::assertCount(2, $commands); + self::assertContainsOnlyInstancesOf(Command::class, $commands); + } + + /** + * @test + */ + public function throwsExceptionOnDuplicateCommand() + { + /** @var PackageInterface */ + $package3 = $this->prophesize(PackageInterface::class); + $package3->getPackagePath()->willReturn($this->rootDirectory->getChild('package3')->url() . '/'); + /** @var PackageInterface */ + $package4 = $this->prophesize(PackageInterface::class); + $package4->getPackagePath()->willReturn($this->rootDirectory->getChild('package4')->url() . '/'); + $package4->getPackageKey()->willReturn('package4'); + + $this->packageManagerProphecy->getActivePackages()->willReturn([$package3->reveal(), $package4->reveal()]); + + $this->expectException(CommandNameAlreadyInUseException::class); + $this->expectExceptionCode(1484486383); + + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + iterator_to_array($commandRegistry); + } + + /** + * @test + */ + public function getCommandByIdentifierReturnsRegisteredCommand() + { + /** @var PackageInterface|ObjectProphecy $package */ + $package = $this->prophesize(PackageInterface::class); + $package->getPackagePath()->willReturn($this->rootDirectory->getChild('package1')->url() . '/'); + $package->getPackageKey()->willReturn('package1'); + + $this->packageManagerProphecy->getActivePackages()->willReturn([$package->reveal()]); + + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + $command = $commandRegistry->getCommandByIdentifier('first:command'); + + self::assertInstanceOf(Command::class, $command); + } + + /** + * @test + */ + public function throwsUnknowCommandExceptionIfUnregisteredCommandIsRequested() + { + $this->packageManagerProphecy->getActivePackages()->willReturn([]); + + $this->expectException(UnknownCommandException::class); + $this->expectExceptionCode(1510906768); + + $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal(), $this->containerProphecy->reveal()); + $commandRegistry->getCommandByIdentifier('foo'); + } +} diff --git a/typo3/sysext/extensionmanager/Configuration/Commands.php b/typo3/sysext/extensionmanager/Configuration/Commands.php deleted file mode 100644 index 22dd86b0cf21c427c744649ea40a2e2d1956b06e..0000000000000000000000000000000000000000 --- a/typo3/sysext/extensionmanager/Configuration/Commands.php +++ /dev/null @@ -1,17 +0,0 @@ -<?php -/** - * Commands to be executed by typo3, where the key of the array - * is the name of the command (to be called as the first argument after typo3). - * Required parameter is the "class" of the command which needs to be a subclass - * of Symfony/Console/Command. - */ -return [ - 'extension:activate' => [ - 'class' => \TYPO3\CMS\Extensionmanager\Command\ActivateExtensionCommand::class, - 'schedulable' => false, - ], - 'extension:deactivate' => [ - 'class' => \TYPO3\CMS\Extensionmanager\Command\DeactivateExtensionCommand::class, - 'schedulable' => false, - ], -]; diff --git a/typo3/sysext/extensionmanager/Configuration/Services.yaml b/typo3/sysext/extensionmanager/Configuration/Services.yaml index c94629a9cd35463e0a79a7084e08d87611eb5cd7..9c547ab8306a25e7e01a627fccf88025dd16b0e5 100644 --- a/typo3/sysext/extensionmanager/Configuration/Services.yaml +++ b/typo3/sysext/extensionmanager/Configuration/Services.yaml @@ -40,3 +40,31 @@ services: identifier: 'legacy-slot' method: 'emitProcessActionsSignal' event: TYPO3\CMS\Extensionmanager\Event\AvailableActionsForExtensionEvent + + TYPO3\CMS\Extensionmanager\Command\ActivateExtensionCommand: + tags: + - name: 'console.command' + command: 'extension:activate' + schedulable: false + - name: 'console.command' + command: 'extensionmanager:extension:install' + alias: true + schedulable: false + - name: 'console.command' + command: 'extension:install' + alias: true + schedulable: false + + TYPO3\CMS\Extensionmanager\Command\DeactivateExtensionCommand: + tags: + - name: 'console.command' + command: 'extension:deactivate' + schedulable: false + - name: 'console.command' + command: 'extensionmanager:extension:uninstall' + alias: true + schedulable: false + - name: 'console.command' + command: 'extension:uninstall' + alias: true + schedulable: false diff --git a/typo3/sysext/impexp/Configuration/Commands.php b/typo3/sysext/impexp/Configuration/Commands.php deleted file mode 100644 index cecbaea9dec4e03541b1d0d26b364a6ebb91f79e..0000000000000000000000000000000000000000 --- a/typo3/sysext/impexp/Configuration/Commands.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php -/** - * Commands to be executed by typo3, where the key of the array - * is the name of the command (to be called as the first argument after typo3). - * Required parameter is the "class" of the command which needs to be a subclass - * of Symfony/Console/Command. - */ -return [ - 'impexp:import' => [ - 'class' => \TYPO3\CMS\Impexp\Command\ImportCommand::class - ] -]; diff --git a/typo3/sysext/impexp/Configuration/Services.yaml b/typo3/sysext/impexp/Configuration/Services.yaml index 4099126b0450823b4e91fee7841d40c4c8af4bb1..321ccd27139c8f0f891badbcfdf29659473c87d0 100644 --- a/typo3/sysext/impexp/Configuration/Services.yaml +++ b/typo3/sysext/impexp/Configuration/Services.yaml @@ -10,6 +10,11 @@ services: TYPO3\CMS\Impexp\Utility\ImportExportUtility: public: true + TYPO3\CMS\Impexp\Command\ImportCommand: + tags: + - name: 'console.command' + command: 'impexp:import' + # Listener for old Signal Slots TYPO3\CMS\Impexp\Compatibility\SlotReplacement: tags: diff --git a/typo3/sysext/install/Classes/ServiceProvider.php b/typo3/sysext/install/Classes/ServiceProvider.php index 0f9475d2248bb8e91fa70fb561fc99acdd8610f9..a1874db01e6f8c9cac491a14e8193300683e9d3b 100644 --- a/typo3/sysext/install/Classes/ServiceProvider.php +++ b/typo3/sysext/install/Classes/ServiceProvider.php @@ -17,6 +17,7 @@ namespace TYPO3\CMS\Install; use Psr\Container\ContainerInterface; use TYPO3\CMS\Core\Configuration\ConfigurationManager; +use TYPO3\CMS\Core\Console\CommandRegistry; use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory; use TYPO3\CMS\Core\DependencyInjection\ContainerBuilder; @@ -45,6 +46,16 @@ class ServiceProvider extends AbstractServiceProvider Service\LoadTcaService::class => [ static::class, 'getLoadTcaService' ], Middleware\Maintenance::class => [ static::class, 'getMaintenanceMiddleware' ], Controller\UpgradeController::class => [ static::class, 'getUpgradeController' ], + Command\LanguagePackCommand::class => [ static::class, 'getLanguagePackCommand' ], + Command\UpgradeWizardRunCommand::class => [ static::class, 'getUpgradeWizardRunCommand' ], + Command\UpgradeWizardListCommand::class => [ static::class, 'getUpgradeWizardListCommand' ], + ]; + } + + public function getExtensions(): array + { + return [ + CommandRegistry::class => [ static::class, 'configureCommands' ], ]; } @@ -101,4 +112,27 @@ class ServiceProvider extends AbstractServiceProvider $container->get(Service\LateBootService::class) ); } + + public static function getLanguagePackCommand(ContainerInterface $container): Command\LanguagePackCommand + { + return new Command\LanguagePackCommand; + } + + public static function getUpgradeWizardRunCommand(ContainerInterface $container): Command\UpgradeWizardRunCommand + { + return new Command\UpgradeWizardRunCommand; + } + + public static function getUpgradeWizardListCommand(ContainerInterface $container): Command\UpgradeWizardListCommand + { + return new Command\UpgradeWizardListCommand; + } + + public static function configureCommands(ContainerInterface $container, CommandRegistry $commandRegistry): CommandRegistry + { + $commandRegistry->addLazyCommand('language:update', Command\LanguagePackCommand::class); + $commandRegistry->addLazyCommand('upgrade:run', Command\UpgradeWizardRunCommand::class); + $commandRegistry->addLazyCommand('upgrade:list', Command\UpgradeWizardListCommand::class); + return $commandRegistry; + } } diff --git a/typo3/sysext/install/Configuration/Commands.php b/typo3/sysext/install/Configuration/Commands.php deleted file mode 100644 index 872a35613cee2a018ccc44fbe8dfb3b00473150c..0000000000000000000000000000000000000000 --- a/typo3/sysext/install/Configuration/Commands.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php -/** - * Commands to be executed by typo3, where the key of the array - * is the name of the command (to be called as the first argument after typo3). - * Required parameter is the "class" of the command which needs to be a subclass - * of Symfony/Console/Command. - * - * example: bin/typo3 language:update - */ -return [ - 'language:update' => [ - 'class' => \TYPO3\CMS\Install\Command\LanguagePackCommand::class - ], - 'upgrade:run' => [ - 'class' => \TYPO3\CMS\Install\Command\UpgradeWizardRunCommand::class - ], - 'upgrade:list' => [ - 'class' => \TYPO3\CMS\Install\Command\UpgradeWizardListCommand::class - ] -]; diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php index f909a31af43fd5e374e5353b0e745b5c2299603c..1f0cf4973a1a3f28e3249d3ba73bcbca3aa7700a 100644 --- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php +++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php @@ -4420,4 +4420,12 @@ return [ 'Deprecation-90258-SimplifiedRTEParserAPI.rst', ], ], + 'TYPO3\CMS\Core\Console\CommandRegistry->getIterator' => [ + 'numberOfMandatoryArguments' => 0, + 'maximumNumberOfArguments' => 0, + 'restFiles' => [ + 'Feature-89139-AddDependencyInjectionSupportForConsoleCommands.rst', + 'Deprecation-89139-ConsoleCommandsConfigurationMigratedToSymfonyServiceTags.rst', + ], + ], ]; diff --git a/typo3/sysext/lowlevel/Configuration/Commands.php b/typo3/sysext/lowlevel/Configuration/Commands.php deleted file mode 100644 index 3b468e21a263205ee4b0f2a75ff0e434965c5434..0000000000000000000000000000000000000000 --- a/typo3/sysext/lowlevel/Configuration/Commands.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php -/** - * Commands to be executed by the typo3 CLI binary, where the key of the array - * is the name of the command (to be called as the first argument after "bin/typo3"). - * Required parameter is the "class" of the command which needs to be a subclass - * of Symfony/Console/Command. - */ -return [ - 'syslog:list' => [ - 'class' => \TYPO3\CMS\Lowlevel\Command\ListSysLogCommand::class - ], - 'cleanup:missingfiles' => [ - 'class' => \TYPO3\CMS\Lowlevel\Command\MissingFilesCommand::class - ], - 'cleanup:lostfiles' => [ - 'class' => \TYPO3\CMS\Lowlevel\Command\LostFilesCommand::class - ], - 'cleanup:multiplereferencedfiles' => [ - 'class' => \TYPO3\CMS\Lowlevel\Command\FilesWithMultipleReferencesCommand::class - ], - 'cleanup:missingrelations' => [ - 'class' => \TYPO3\CMS\Lowlevel\Command\MissingRelationsCommand::class - ], - 'cleanup:deletedrecords' => [ - 'class' => \TYPO3\CMS\Lowlevel\Command\DeletedRecordsCommand::class - ], - 'cleanup:orphanrecords' => [ - 'class' => \TYPO3\CMS\Lowlevel\Command\OrphanRecordsCommand::class - ], - 'cleanup:flexforms' => [ - 'class' => \TYPO3\CMS\Lowlevel\Command\CleanFlexFormsCommand::class, - ] -]; diff --git a/typo3/sysext/lowlevel/Configuration/Services.yaml b/typo3/sysext/lowlevel/Configuration/Services.yaml index 6ded070b54e9a8c3e7c63777cea35c50120bd7b0..a3f390874b98dfaa9967683db060b2786fd936d1 100644 --- a/typo3/sysext/lowlevel/Configuration/Services.yaml +++ b/typo3/sysext/lowlevel/Configuration/Services.yaml @@ -6,3 +6,43 @@ services: TYPO3\CMS\Lowlevel\: resource: '../Classes/*' + + TYPO3\CMS\Lowlevel\Command\ListSysLogCommand: + tags: + - name: 'console.command' + command: 'syslog:list' + + TYPO3\CMS\Lowlevel\Command\MissingFilesCommand: + tags: + - name: 'console.command' + command: 'cleanup:missingfiles' + + TYPO3\CMS\Lowlevel\Command\LostFilesCommand: + tags: + - name: 'console.command' + command: 'cleanup:lostfiles' + + TYPO3\CMS\Lowlevel\Command\FilesWithMultipleReferencesCommand: + tags: + - name: 'console.command' + command: 'cleanup:multiplereferencedfiles' + + TYPO3\CMS\Lowlevel\Command\MissingRelationsCommand: + tags: + - name: 'console.command' + command: 'cleanup:missingrelations' + + TYPO3\CMS\Lowlevel\Command\DeletedRecordsCommand: + tags: + - name: 'console.command' + command: 'cleanup:deletedrecords' + + TYPO3\CMS\Lowlevel\Command\OrphanRecordsCommand: + tags: + - name: 'console.command' + command: 'cleanup:orphanrecords' + + TYPO3\CMS\Lowlevel\Command\CleanFlexFormsCommand: + tags: + - name: 'console.command' + command: 'cleanup:flexforms' diff --git a/typo3/sysext/redirects/Configuration/Commands.php b/typo3/sysext/redirects/Configuration/Commands.php deleted file mode 100644 index b9687f07e55fd8d8b76e5f4df04991adcd362a77..0000000000000000000000000000000000000000 --- a/typo3/sysext/redirects/Configuration/Commands.php +++ /dev/null @@ -1,13 +0,0 @@ -<?php -/** - * Commands to be executed by typo3, where the key of the array - * is the name of the command (to be called as the first argument after typo3). - * Required parameter is the "class" of the command which needs to be a subclass - * of Symfony/Console/Command. - */ -return [ - 'redirects:checkintegrity' => [ - 'class' => \TYPO3\CMS\Redirects\Command\CheckIntegrityCommand::class, - 'schedulable' => true, - ], -]; diff --git a/typo3/sysext/redirects/Configuration/Services.yaml b/typo3/sysext/redirects/Configuration/Services.yaml index 17372701f400c95078d56ec0ea3d05a8f1f3f94c..eb29c25540e054035896f96b20582269d7fad3f0 100644 --- a/typo3/sysext/redirects/Configuration/Services.yaml +++ b/typo3/sysext/redirects/Configuration/Services.yaml @@ -13,6 +13,11 @@ services: TYPO3\CMS\Redirects\Hooks\DataHandlerSlugUpdateHook: public: true + TYPO3\CMS\Redirects\Command\CheckIntegrityCommand: + tags: + - name: 'console.command' + command: 'redirects:checkintegrity' + TYPO3\CMS\Redirects\EventListener\RecordHistoryRollbackEventsListener: tags: - name: event.listener diff --git a/typo3/sysext/scheduler/Configuration/Commands.php b/typo3/sysext/scheduler/Configuration/Commands.php deleted file mode 100644 index d6d3aa2fe051af9284eadbff8dd1f3822f78a6e8..0000000000000000000000000000000000000000 --- a/typo3/sysext/scheduler/Configuration/Commands.php +++ /dev/null @@ -1,14 +0,0 @@ -<?php -/** - * Commands to be executed by typo3, where the key of the array - * is the name of the command (to be called as the first argument after typo3). - * Required parameter is the "class" of the command which needs to be a subclass - * of Symfony/Console/Command. - */ -return [ - 'scheduler:run' => [ - 'class' => \TYPO3\CMS\Scheduler\Command\SchedulerCommand::class, - // command must not be schedulable, otherwise we'll get an endless recursion - 'schedulable' => false, - ] -]; diff --git a/typo3/sysext/scheduler/Configuration/Services.yaml b/typo3/sysext/scheduler/Configuration/Services.yaml index c719171541e8ba1cfde0467afba4cae5485b79aa..b7456c24a3d60263aa123eea56f90eb7862dda60 100644 --- a/typo3/sysext/scheduler/Configuration/Services.yaml +++ b/typo3/sysext/scheduler/Configuration/Services.yaml @@ -7,6 +7,12 @@ services: TYPO3\CMS\Scheduler\: resource: '../Classes/*' + TYPO3\CMS\Scheduler\Command\SchedulerCommand: + tags: + - name: 'console.command' + command: 'scheduler:run' + schedulable: false + TYPO3\CMS\Scheduler\SystemInformation\ToolbarItemProvider: tags: - name: event.listener diff --git a/typo3/sysext/workspaces/Configuration/Commands.php b/typo3/sysext/workspaces/Configuration/Commands.php deleted file mode 100644 index e156d33fa66cfa741c05e8400763629b65edfeb7..0000000000000000000000000000000000000000 --- a/typo3/sysext/workspaces/Configuration/Commands.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php -/** - * Commands to be executed by the typo3 CLI binary, where the key of the array - * is the name of the command (to be called as the first argument after "bin/typo3"). - * Required parameter is the "class" of the command which needs to be a subclass - * of Symfony/Console/Command. - */ -return [ - 'cleanup:versions' => [ - 'class' => \TYPO3\CMS\Workspaces\Command\WorkspaceVersionRecordsCommand::class, - ], - 'cleanup:previewlinks' => [ - 'class' => \TYPO3\CMS\Workspaces\Command\CleanupPreviewLinksCommand::class, - ], - 'workspace:autopublish' => [ - 'class' => \TYPO3\CMS\Workspaces\Command\AutoPublishCommand::class, - ], -]; diff --git a/typo3/sysext/workspaces/Configuration/Services.yaml b/typo3/sysext/workspaces/Configuration/Services.yaml index 9c62f633de7cbe600cf03e5cf8d68873a5ffc1c8..2649612811def30f370d5e2807d5000cc1485d09 100644 --- a/typo3/sysext/workspaces/Configuration/Services.yaml +++ b/typo3/sysext/workspaces/Configuration/Services.yaml @@ -15,6 +15,21 @@ services: TYPO3\CMS\Workspaces\Service\GridDataService: public: true + TYPO3\CMS\Workspaces\Command\WorkspaceVersionRecordsCommand: + tags: + - name: 'console.command' + command: 'cleanup:versions' + + TYPO3\CMS\Workspaces\Command\CleanupPreviewLinksCommand: + tags: + - name: 'console.command' + command: 'cleanup:previewlinks' + + TYPO3\CMS\Workspaces\Command\AutoPublishCommand: + tags: + - name: 'console.command' + command: 'workspace:autopublish' + TYPO3\CMS\Workspaces\Compatibility\SlotReplacement: tags: - name: event.listener