[TASK] Add available commands to console output
[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\Core\Bootstrap;
22 use TYPO3\CMS\Core\Package\PackageManager;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24
25 /**
26 * Command Line Interface Request Handler dealing with registered commands.
27 */
28 class CommandRequestHandler implements RequestHandlerInterface
29 {
30 /**
31 * Instance of the current TYPO3 bootstrap
32 * @var Bootstrap
33 */
34 protected $bootstrap;
35
36 /**
37 * Instance of the symfony application
38 * @var Application
39 */
40 protected $application;
41
42 /**
43 * @var []
44 */
45 protected $availableCommands;
46
47 /**
48 * Constructor handing over the bootstrap
49 *
50 * @param Bootstrap $bootstrap
51 */
52 public function __construct(Bootstrap $bootstrap)
53 {
54 $this->bootstrap = $bootstrap;
55 $this->application = new Application('TYPO3 CMS', TYPO3_version);
56 }
57
58 /**
59 * Handles any commandline request
60 *
61 * @param InputInterface $input
62 * @return void
63 */
64 public function handleRequest(InputInterface $input)
65 {
66 $output = new ConsoleOutput();
67
68 $this->bootstrap->loadExtensionTables();
69
70 // Check if the command to run needs a backend user to be loaded
71 $command = $this->getCommandToRun($input);
72 foreach ($this->availableCommands as $data) {
73 if ($data['command'] !== $command) {
74 continue;
75 }
76 if (isset($data['user'])) {
77 $this->initializeBackendUser($data['user']);
78 }
79 }
80
81 // Make sure output is not buffered, so command-line output and interaction can take place
82 $this->bootstrap->endOutputBufferingAndCleanPreviousOutput();
83
84 if (!$command) {
85 $cliKeys = array_keys($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys']);
86
87 $output->writeln('Old entrypoint keys available:');
88 asort($cliKeys);
89 foreach ($cliKeys as $key => $value) {
90 $output->writeln(' ' . $value);
91 }
92 $output->writeln('');
93 $output->writeln('TYPO3 Console Commands:');
94 }
95
96 $exitCode = $this->application->run($input, $output);
97 exit($exitCode);
98 }
99
100 /**
101 * If the backend script is in CLI mode, it will try to load a backend user named by the CLI module name (in lowercase)
102 *
103 * @param string $userName the name of the module registered inside $TYPO3_CONF_VARS[SC_OPTIONS][GLOBAL][cliKeys] as second parameter
104 * @throws \RuntimeException if a non-admin Backend user could not be loaded
105 */
106 protected function initializeBackendUser($userName)
107 {
108 $this->bootstrap->initializeBackendUser();
109
110 $GLOBALS['BE_USER']->setBeUserByName($userName);
111 if (!$GLOBALS['BE_USER']->user['uid']) {
112 throw new \RuntimeException('No backend user named "' . $userName . '" was found!', 1476107260);
113 }
114
115 $this->bootstrap
116 ->initializeBackendAuthentication()
117 ->initializeLanguageObject();
118 }
119
120 /**
121 * This request handler can handle any CLI request
122 *
123 * @param InputInterface $input
124 * @return bool Always TRUE
125 */
126 public function canHandleRequest(InputInterface $input)
127 {
128 $this->populateAvailableCommands();
129 return true;
130 }
131
132 /**
133 * Returns the priority - how eager the handler is to actually handle the request.
134 *
135 * @return int The priority of the request handler.
136 */
137 public function getPriority()
138 {
139 return 50;
140 }
141
142 /**
143 *
144 * @param InputInterface $input
145 * @return bool|Command
146 */
147 protected function getCommandToRun(InputInterface $input)
148 {
149 $firstArgument = $input->getFirstArgument();
150 try {
151 return $this->application->find($firstArgument);
152 } catch (\InvalidArgumentException $e) {
153 return false;
154 }
155 }
156
157 /**
158 * put all available commands inside the application
159 */
160 protected function populateAvailableCommands()
161 {
162 $this->availableCommands = $this->getAvailableCommands();
163 foreach ($this->availableCommands as $name => $data) {
164 /** @var Command $cmd */
165 $cmd = GeneralUtility::makeInstance($data['class'], $name);
166 $this->application->add($cmd);
167 $this->availableCommands[$name]['command'] = $cmd;
168 }
169 }
170
171 /**
172 * Fetches all commands registered via Commands.php of all active packages
173 *
174 * @return array
175 */
176 protected function getAvailableCommands()
177 {
178 /** @var PackageManager $packageManager */
179 $packageManager = Bootstrap::getInstance()->getEarlyInstance(PackageManager::class);
180 $availableCommands = [];
181
182 foreach ($packageManager->getActivePackages() as $package) {
183 $commandsOfExtension = $package->getPackagePath() . 'Configuration/Commands.php';
184 if (@is_file($commandsOfExtension)) {
185 $commands = require_once $commandsOfExtension;
186 if (is_array($commands)) {
187 $availableCommands = array_merge($availableCommands, $commands);
188 }
189 }
190 }
191
192 return $availableCommands;
193 }
194 }