[BUGFIX] Populate loaded commands after ext_tables is loaded
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Console / CommandRequestHandler.php
1 <?php
2 namespace TYPO3\CMS\Core\Console;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Symfony\Component\Console\Application;
18 use Symfony\Component\Console\Command\Command;
19 use Symfony\Component\Console\Input\InputInterface;
20 use Symfony\Component\Console\Output\ConsoleOutput;
21 use TYPO3\CMS\Core\Authentication\CommandLineUserAuthentication;
22 use TYPO3\CMS\Core\Core\Bootstrap;
23 use TYPO3\CMS\Core\Package\PackageManager;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25
26 /**
27 * Command Line Interface Request Handler dealing with registered commands.
28 */
29 class CommandRequestHandler implements RequestHandlerInterface
30 {
31 /**
32 * Instance of the current TYPO3 bootstrap
33 * @var Bootstrap
34 */
35 protected $bootstrap;
36
37 /**
38 * Instance of the symfony application
39 * @var Application
40 */
41 protected $application;
42
43 /**
44 * Constructor handing over the bootstrap
45 *
46 * @param Bootstrap $bootstrap
47 */
48 public function __construct(Bootstrap $bootstrap)
49 {
50 $this->bootstrap = $bootstrap;
51 $this->application = new Application('TYPO3 CMS', TYPO3_version);
52 }
53
54 /**
55 * Handles any commandline request
56 *
57 * @param InputInterface $input
58 */
59 public function handleRequest(InputInterface $input)
60 {
61 $output = new ConsoleOutput();
62
63 $this->bootstrap
64 ->loadExtTables()
65 // create the BE_USER object (not logged in yet)
66 ->initializeBackendUser(CommandLineUserAuthentication::class)
67 ->initializeLanguageObject()
68 // Make sure output is not buffered, so command-line output and interaction can take place
69 ->endOutputBufferingAndCleanPreviousOutput();
70
71 $this->populateAvailableCommands();
72
73 $exitCode = $this->application->run($input, $output);
74 exit($exitCode);
75 }
76
77 /**
78 * This request handler can handle any CLI request
79 *
80 * @param InputInterface $input
81 * @return bool Always TRUE
82 */
83 public function canHandleRequest(InputInterface $input)
84 {
85 return true;
86 }
87
88 /**
89 * Returns the priority - how eager the handler is to actually handle the request.
90 *
91 * @return int The priority of the request handler.
92 */
93 public function getPriority()
94 {
95 return 50;
96 }
97
98 /**
99 * Put all available commands inside the application
100 */
101 protected function populateAvailableCommands()
102 {
103 /** @var PackageManager $packageManager */
104 $packageManager = Bootstrap::getInstance()->getEarlyInstance(PackageManager::class);
105
106 foreach ($packageManager->getActivePackages() as $package) {
107 $commandsOfExtension = $package->getPackagePath() . 'Configuration/Commands.php';
108 if (@is_file($commandsOfExtension)) {
109 $commands = require_once $commandsOfExtension;
110 if (is_array($commands)) {
111 foreach ($commands as $commandName => $commandDescription) {
112 /** @var Command $cmd */
113 $cmd = GeneralUtility::makeInstance($commandDescription['class'], $commandName);
114 // Check if the command name is already in use
115 if ($this->application->has($commandName)) {
116 throw new CommandNameAlreadyInUseException('Command "' . $commandName . '" registered by "' . $package->getPackageKey() . '" is already in use', 1484486383);
117 }
118 $this->application->add($cmd);
119 }
120 }
121 }
122 }
123 }
124 }