diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-80452-ExtbaseCLICommandsAvailableViaNewCLIAPI.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-80452-ExtbaseCLICommandsAvailableViaNewCLIAPI.rst new file mode 100644 index 0000000000000000000000000000000000000000..9312119b0c39002bb2274fa3ff9e2d1d92477b22 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-80452-ExtbaseCLICommandsAvailableViaNewCLIAPI.rst @@ -0,0 +1,18 @@ +.. include:: ../../Includes.txt + +================================================================ +Feature: #80452 - Extbase CLI commands available via new CLI API +================================================================ + +See :issue:`80452` + +Description +=========== + +Any Extbase Command Controller can now be accessed via the new Symfony Console CLI entrypoint by +simply calling `typo3/sysext/core/bin/typo3 controller:command`. + +Using the existing CLI entrypoint via `typo3/cli_dispatch.phpsh extbase controller:command` still +works as expected. + +.. index:: CLI \ No newline at end of file diff --git a/typo3/sysext/extbase/Classes/Command/CoreCommand.php b/typo3/sysext/extbase/Classes/Command/CoreCommand.php new file mode 100644 index 0000000000000000000000000000000000000000..15f1bff454f64796d25069260e47f673fb001c1a --- /dev/null +++ b/typo3/sysext/extbase/Classes/Command/CoreCommand.php @@ -0,0 +1,84 @@ +<?php +namespace TYPO3\CMS\Extbase\Command; + +/* + * 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\Console\Application; +use Symfony\Component\Console\Command\Command; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Core\Bootstrap; +use TYPO3\CMS\Extbase\Mvc\Cli\CommandManager; +use TYPO3\CMS\Extbase\Object\ObjectManager; + +/** + * Main call to register any Extbase command from Extbase command controllers + * + * Fetches all registered Extbase commands and adds them to the application as custom Extbase commands + */ +class CoreCommand extends Command +{ + /** + * @var Bootstrap + */ + protected $extbaseBootstrap; + + /** + * Configure the command, since this is a command + */ + protected function configure() + { + $this->setHidden(true); + } + + /** + * Sets the application instance for this command. + * This is done in setApplication() because configure() is called too early to do it in that place. + * The method 'setApplication()' is done right afterwards but has the application object to call. + * Then registers additional commands that act as wrappers to the actual Extbase commands. + * + * @param Application $application An Application instance + */ + public function setApplication(Application $application = null) + { + parent::setApplication($application); + + // Find any registered Extbase commands + $this->extbaseBootstrap = GeneralUtility::makeInstance(Bootstrap::class); + $this->extbaseBootstrap->initialize([]); + + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + + /** @var CommandManager $commandManager */ + $commandManager = $objectManager->get(CommandManager::class); + $commands = $commandManager->getAvailableCommands(); + foreach ($commands as $command) { + $commandName = $commandManager->getShortestIdentifierForCommand($command); + $fullCommandName = $command->getCommandIdentifier(); + if ($fullCommandName === 'extbase:help:error' || $fullCommandName === 'extbase:help:helpstub') { + continue; + } + if ($commandName === 'help') { + $commandName = 'extbase:help'; + } + $extbaseCommand = GeneralUtility::makeInstance(ExtbaseCommand::class, $fullCommandName); + + if ($commandName !== $fullCommandName) { + $extbaseCommand->setAliases([$commandName]); + } + + $extbaseCommand->setExtbaseCommand($command); + $this->getApplication()->add($extbaseCommand); + } + } +} diff --git a/typo3/sysext/extbase/Classes/Command/ExtbaseCommand.php b/typo3/sysext/extbase/Classes/Command/ExtbaseCommand.php new file mode 100644 index 0000000000000000000000000000000000000000..34c000cb14f56203bfef477a08d6b3c6aad56537 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Command/ExtbaseCommand.php @@ -0,0 +1,85 @@ +<?php +namespace TYPO3\CMS\Extbase\Command; + +/* + * 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\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Core\Bootstrap; + +/** + * Wrapper to wrap an Extbase command from a command controller into a Symfony Command + */ +class ExtbaseCommand extends Command +{ + /** + * Extbase's command + * @var \TYPO3\CMS\Extbase\Mvc\Cli\Command + */ + protected $command; + + /** + * Extbase has its own validation logic, so it is disabled in this place + */ + protected function configure() + { + $this->ignoreValidationErrors(); + } + + /** + * Sets the extbase command to be used for fetching the description etc. + * + * @param \TYPO3\CMS\Extbase\Mvc\Cli\Command $command + */ + public function setExtbaseCommand(\TYPO3\CMS\Extbase\Mvc\Cli\Command $command) + { + $this->command = $command; + } + + /** + * Sets the application instance for this command. + * Also uses the setApplication call now, as $this->configure() is called + * too early + * + * @param Application $application An Application instance + */ + public function setApplication(Application $application = null) + { + parent::setApplication($application); + $description = $this->command->getDescription(); + $description = str_replace(LF, ' ', $description); + $this->setDescription($description); + } + + /** + * Executes the command to find any Extbase command + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + // ugly hack because extbase only knows "help" (hardcoded, but already defined by symfony) + // and "extbase:help:help" + if ($_SERVER['argv'][1] === 'extbase:help') { + $_SERVER['argv'][1] = 'extbase:help:help'; + } + $bootstrap = GeneralUtility::makeInstance(Bootstrap::class); + $bootstrap->run('', []); + } +} diff --git a/typo3/sysext/extbase/Classes/Command/HelpCommand.php b/typo3/sysext/extbase/Classes/Command/HelpCommand.php new file mode 100644 index 0000000000000000000000000000000000000000..065eb775f4f616a387beaa2bc37bb175c59cc8d8 --- /dev/null +++ b/typo3/sysext/extbase/Classes/Command/HelpCommand.php @@ -0,0 +1,89 @@ +<?php +namespace TYPO3\CMS\Extbase\Command; + +/* + * 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\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Core\Bootstrap; + +/** + * Extends the help command of symfony to show the specific help for Extbase commands + */ +class HelpCommand extends \Symfony\Component\Console\Command\HelpCommand +{ + /** + * This needs to be re-set as the parent command has this property declared as "private" as well. + * + * @var Command + */ + private $command; + + /** + * {@inheritdoc} + */ + protected function configure() + { + parent::configure(); + $this->setAliases([]); + } + + /** + * Sets the command. + * + * @param Command $command The command to set + */ + public function setCommand(Command $command) + { + $this->command = $command; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (null === $this->command) { + $this->command = $this->getApplication()->find($input->getArgument('command_name')); + } + + // Extbase help was explicitly called + if ($input->getArgument('command') === 'extbase:help' || $input->getArgument('command') === 'extbase:help:help') { + $_SERVER['argv'][1] = 'extbase:help:help'; + $bootstrap = GeneralUtility::makeInstance(Bootstrap::class); + $bootstrap->run('', []); + + // An extbase command was originally called, but is now required to show the help information + } elseif ($this->command instanceof ExtbaseCommand) { + // Ugly hack to modify 'argv' so the help command for a specific command is shown + $args = [$_SERVER['argv'][0], 'help']; + foreach ($_SERVER['argv'] as $k => $value) { + if ($k === 0 || $value === '--help' || $value === '-h') { + continue; + } + $args[] = $value; + } + $_SERVER['argv'] = $args; + + // run Extbase bootstrap + $bootstrap = GeneralUtility::makeInstance(Bootstrap::class); + $bootstrap->run('', []); + } else { + // Any other symfony command should just show up the regular info + parent::execute($input, $output); + } + } +} diff --git a/typo3/sysext/extbase/Classes/Mvc/Cli/RequestHandler.php b/typo3/sysext/extbase/Classes/Mvc/Cli/RequestHandler.php index f2d3b2047b42b4eba6e6e7f1aaa5c11700be8c30..01f4f7f00be93581eb00f49dbf1ad301b6985cdc 100644 --- a/typo3/sysext/extbase/Classes/Mvc/Cli/RequestHandler.php +++ b/typo3/sysext/extbase/Classes/Mvc/Cli/RequestHandler.php @@ -85,7 +85,12 @@ class RequestHandler implements \TYPO3\CMS\Extbase\Mvc\RequestHandlerInterface if ($callingScript !== $_SERVER['_']) { $callingScript = $_SERVER['_'] . ' ' . $callingScript; } - $request = $this->requestBuilder->build($commandLine, $callingScript . ' extbase'); + + // Add the "extbase" prefix for the cli_dispatch command line tool + if (strpos($callingScript, 'cli_dispatch') !== false) { + $callingScript .= ' extbase'; + } + $request = $this->requestBuilder->build($commandLine, $callingScript); /** @var $response \TYPO3\CMS\Extbase\Mvc\Cli\Response */ $response = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\Response::class); $this->dispatcher->dispatch($request, $response); diff --git a/typo3/sysext/extbase/Configuration/Commands.php b/typo3/sysext/extbase/Configuration/Commands.php new file mode 100644 index 0000000000000000000000000000000000000000..7bb11c5e143cfe095c0af027a6b1af7d4d64b12c --- /dev/null +++ b/typo3/sysext/extbase/Configuration/Commands.php @@ -0,0 +1,16 @@ +<?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 [ + 'extbase' => [ + 'class' => \TYPO3\CMS\Extbase\Command\CoreCommand::class + ], + // Overriding Symfony Help command to use Extbase-specific output + '_extbase_help' => [ + 'class' => \TYPO3\CMS\Extbase\Command\HelpCommand::class + ] +];