[TASK] Streamline phpdoc annotations in EXT:extbase
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Controller / CommandController.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Mvc\Controller;
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 TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
18 use TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition;
19 use TYPO3\CMS\Extbase\Mvc\Cli\ConsoleOutput;
20 use TYPO3\CMS\Extbase\Mvc\Cli\Request;
21 use TYPO3\CMS\Extbase\Mvc\Cli\Response;
22 use TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentTypeException;
23 use TYPO3\CMS\Extbase\Mvc\Exception\NoSuchCommandException;
24 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
25 use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
26 use TYPO3\CMS\Extbase\Mvc\RequestInterface;
27 use TYPO3\CMS\Extbase\Mvc\ResponseInterface;
28 use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
29 use TYPO3\CMS\Extbase\Reflection\ReflectionService;
30
31 /**
32 * A controller which processes requests from the command line
33 *
34 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use symfony/console commands instead.
35 */
36 class CommandController implements CommandControllerInterface
37 {
38 /**
39 * @var Request
40 */
41 protected $request;
42
43 /**
44 * @var Response
45 */
46 protected $response;
47
48 /**
49 * @var Arguments
50 */
51 protected $arguments;
52
53 /**
54 * Name of the command method
55 *
56 * @var string
57 */
58 protected $commandMethodName = '';
59
60 /**
61 * Whether the command needs admin access to perform its job
62 *
63 * @var bool
64 */
65 protected $requestAdminPermissions = false;
66
67 /**
68 * @var ReflectionService
69 */
70 protected $reflectionService;
71
72 /**
73 * @var ObjectManagerInterface
74 */
75 protected $objectManager;
76
77 /**
78 * @var ConsoleOutput
79 */
80 protected $output;
81
82 public function __construct()
83 {
84 trigger_error('Extbase Command Controllers will be removed in TYPO3 v10.0. Migrate to symfony/console commands instead.', E_USER_DEPRECATED);
85 }
86
87 /**
88 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
89 */
90 public function injectObjectManager(ObjectManagerInterface $objectManager)
91 {
92 $this->objectManager = $objectManager;
93 }
94
95 /**
96 * @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
97 */
98 public function injectReflectionService(ReflectionService $reflectionService)
99 {
100 $this->reflectionService = $reflectionService;
101 }
102
103 /**
104 * Checks if the current request type is supported by the controller.
105 *
106 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The current request
107 * @return bool TRUE if this request type is supported, otherwise FALSE
108 */
109 public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request)
110 {
111 return $request instanceof Request;
112 }
113
114 /**
115 * Processes a command line request.
116 *
117 * @param RequestInterface $request The request object
118 * @param ResponseInterface $response The response, modified by this handler
119 * @throws UnsupportedRequestTypeException if the controller doesn't support the current request type
120 */
121 public function processRequest(RequestInterface $request, ResponseInterface $response)
122 {
123 if (!$this->canProcessRequest($request)) {
124 throw new UnsupportedRequestTypeException(sprintf('%s only supports command line requests – requests of type "%s" given.', static::class, get_class($request)), 1300787096);
125 }
126
127 $this->request = $request;
128 $this->request->setDispatched(true);
129 $this->response = $response;
130
131 $this->commandMethodName = $this->resolveCommandMethodName();
132 $this->output = $this->objectManager->get(ConsoleOutput::class);
133 $this->arguments = $this->objectManager->get(Arguments::class);
134 $this->initializeCommandMethodArguments();
135 $this->mapRequestArgumentsToControllerArguments();
136 $this->initializeBackendAuthentication();
137 $this->callCommandMethod();
138 }
139
140 /**
141 * Resolves and checks the current command method name
142 *
143 * Note: The resulting command method name might not have the correct case, which isn't a problem because PHP is
144 * case insensitive regarding method names.
145 *
146 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchCommandException
147 * @return string Method name of the current command
148 * @throws NoSuchCommandException
149 */
150 protected function resolveCommandMethodName()
151 {
152 $commandMethodName = $this->request->getControllerCommandName() . 'Command';
153 if (!is_callable([$this, $commandMethodName])) {
154 throw new NoSuchCommandException(sprintf('A command method "%s()" does not exist in controller "%s".', $commandMethodName, static::class), 1300902143);
155 }
156 return $commandMethodName;
157 }
158
159 /**
160 * Initializes the arguments array of this controller by creating an empty argument object for each of the
161 * method arguments found in the designated command method.
162 *
163 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentTypeException
164 * @throws InvalidArgumentTypeException
165 */
166 protected function initializeCommandMethodArguments()
167 {
168 $methodParameters = $this->reflectionService
169 ->getClassSchema(static::class)
170 ->getMethod($this->commandMethodName)['params'] ?? [];
171
172 foreach ($methodParameters as $parameterName => $parameterInfo) {
173 $dataType = null;
174 if (isset($parameterInfo['type'])) {
175 $dataType = $parameterInfo['type'];
176 } elseif ($parameterInfo['array']) {
177 $dataType = 'array';
178 }
179 if ($dataType === null) {
180 throw new InvalidArgumentTypeException(sprintf('The argument type for parameter $%s of method %s->%s() could not be detected.', $parameterName, static::class, $this->commandMethodName), 1306755296);
181 }
182 $defaultValue = ($parameterInfo['defaultValue'] ?? null);
183 $this->arguments->addNewArgument($parameterName, $dataType, $parameterInfo['optional'] === false, $defaultValue);
184 }
185 }
186
187 /**
188 * Maps arguments delivered by the request object to the local controller arguments.
189 */
190 protected function mapRequestArgumentsToControllerArguments()
191 {
192 /** @var Argument $argument */
193 foreach ($this->arguments as $argument) {
194 $argumentName = $argument->getName();
195 if ($this->request->hasArgument($argumentName)) {
196 $argument->setValue($this->request->getArgument($argumentName));
197 continue;
198 }
199 if (!$argument->isRequired()) {
200 continue;
201 }
202 $argumentValue = null;
203 $commandArgumentDefinition = $this->objectManager->get(CommandArgumentDefinition::class, $argumentName, true, null);
204 while ($argumentValue === null) {
205 $argumentValue = $this->output->ask(sprintf('<comment>Please specify the required argument "%s":</comment> ', $commandArgumentDefinition->getDashedName()));
206 }
207 $argument->setValue($argumentValue);
208 }
209 }
210
211 /**
212 * Initializes and ensures authenticated backend access
213 */
214 protected function initializeBackendAuthentication()
215 {
216 $backendUserAuthentication = $this->getBackendUserAuthentication();
217 if ($backendUserAuthentication !== null) {
218 $backendUserAuthentication->backendCheckLogin();
219 }
220 }
221
222 /**
223 * Forwards the request to another command and / or CommandController.
224 *
225 * Request is directly transferred to the other command / controller
226 * without the need for a new request.
227 *
228 * @param string $commandName
229 * @param string $controllerObjectName
230 * @param array $arguments
231 * @throws StopActionException
232 */
233 protected function forward($commandName, $controllerObjectName = null, array $arguments = [])
234 {
235 $this->request->setDispatched(false);
236 $this->request->setControllerCommandName($commandName);
237 if ($controllerObjectName !== null) {
238 $this->request->setControllerObjectName($controllerObjectName);
239 }
240 $this->request->setArguments($arguments);
241
242 $this->arguments->removeAll();
243 throw new StopActionException('forward', 1476107661);
244 }
245
246 /**
247 * Calls the specified command method and passes the arguments.
248 *
249 * If the command returns a string, it is appended to the content in the
250 * response object. If the command doesn't return anything and a valid
251 * view exists, the view is rendered automatically.
252 */
253 protected function callCommandMethod()
254 {
255 $preparedArguments = [];
256 /** @var Argument $argument */
257 foreach ($this->arguments as $argument) {
258 $preparedArguments[] = $argument->getValue();
259 }
260 $commandResult = call_user_func_array([$this, $this->commandMethodName], $preparedArguments);
261 if (is_string($commandResult) && $commandResult !== '') {
262 $this->response->appendContent($commandResult);
263 } elseif (is_object($commandResult) && method_exists($commandResult, '__toString')) {
264 $this->response->appendContent((string)$commandResult);
265 }
266 }
267
268 /**
269 * Outputs specified text to the console window
270 * You can specify arguments that will be passed to the text via sprintf
271 *
272 * @see http://www.php.net/sprintf
273 * @param string $text Text to output
274 * @param array $arguments Optional arguments to use for sprintf
275 */
276 protected function output($text, array $arguments = [])
277 {
278 $this->output->output($text, $arguments);
279 }
280
281 /**
282 * Outputs specified text to the console window and appends a line break
283 *
284 * @param string $text Text to output
285 * @param array $arguments Optional arguments to use for sprintf
286 * @see output()
287 */
288 protected function outputLine($text = '', array $arguments = [])
289 {
290 $this->output->outputLine($text, $arguments);
291 }
292
293 /**
294 * Formats the given text to fit into MAXIMUM_LINE_LENGTH and outputs it to the
295 * console window
296 *
297 * @param string $text Text to output
298 * @param array $arguments Optional arguments to use for sprintf
299 * @param int $leftPadding The number of spaces to use for indentation
300 * @see outputLine()
301 */
302 protected function outputFormatted($text = '', array $arguments = [], $leftPadding = 0)
303 {
304 $this->output->outputFormatted($text, $arguments, $leftPadding);
305 }
306
307 /**
308 * Exits the CLI through the dispatcher
309 * An exit status code can be specified @see http://www.php.net/exit
310 *
311 * @param int $exitCode Exit code to return on exit
312 * @throws StopActionException
313 */
314 protected function quit($exitCode = 0)
315 {
316 $this->response->setExitCode($exitCode);
317 throw new StopActionException('quit', 1476107681);
318 }
319
320 /**
321 * Sends the response and exits the CLI without any further code execution
322 * Should be used for commands that flush code caches.
323 *
324 * @param int $exitCode Exit code to return on exit
325 */
326 protected function sendAndExit($exitCode = 0)
327 {
328 $this->response->send();
329 exit($exitCode);
330 }
331
332 /**
333 * Returns the global BackendUserAuthentication object.
334 *
335 * @return BackendUserAuthentication|null
336 */
337 protected function getBackendUserAuthentication()
338 {
339 return $GLOBALS['BE_USER'] ?? null;
340 }
341 }