[CLEANUP] Replace strlen() with === for zero length check
[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\AbstractUserAuthentication;
18 use TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition;
19
20 /**
21 * A controller which processes requests from the command line
22 *
23 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
24 */
25 class CommandController implements CommandControllerInterface {
26
27 const MAXIMUM_LINE_LENGTH = 79;
28
29 /**
30 * @var \TYPO3\CMS\Extbase\Mvc\Cli\Request
31 */
32 protected $request;
33
34 /**
35 * @var \TYPO3\CMS\Extbase\Mvc\Cli\Response
36 */
37 protected $response;
38
39 /**
40 * @var \TYPO3\CMS\Extbase\Mvc\Controller\Arguments
41 */
42 protected $arguments;
43
44 /**
45 * Name of the command method
46 *
47 * @var string
48 */
49 protected $commandMethodName = '';
50
51 /**
52 * Whether the command needs admin access to perform its job
53 *
54 * @var bool
55 * @api
56 */
57 protected $requestAdminPermissions = FALSE;
58
59 /**
60 * @var AbstractUserAuthentication
61 */
62 protected $userAuthentication;
63
64 /**
65 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
66 * @inject
67 */
68 protected $reflectionService;
69
70 /**
71 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
72 */
73 protected $objectManager;
74
75 /**
76 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
77 * @return void
78 */
79 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager) {
80 $this->objectManager = $objectManager;
81 $this->arguments = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Controller\Arguments::class);
82 $this->userAuthentication = isset($GLOBALS['BE_USER']) ? $GLOBALS['BE_USER'] : NULL;
83 }
84
85 /**
86 * Checks if the current request type is supported by the controller.
87 *
88 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The current request
89 * @return bool TRUE if this request type is supported, otherwise FALSE
90 */
91 public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request) {
92 return $request instanceof \TYPO3\CMS\Extbase\Mvc\Cli\Request;
93 }
94
95 /**
96 * Processes a command line request.
97 *
98 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request object
99 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, modified by this controller
100 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
101 * @return void
102 * @api
103 */
104 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response) {
105 if (!$this->canProcessRequest($request)) {
106 throw new \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException(get_class($this) . ' does not support requests of type "' . get_class($request) . '".', 1300787096);
107 }
108 $this->request = $request;
109 $this->request->setDispatched(TRUE);
110 $this->response = $response;
111 $this->commandMethodName = $this->resolveCommandMethodName();
112 $this->initializeCommandMethodArguments();
113 $this->mapRequestArgumentsToControllerArguments();
114 $this->callCommandMethod();
115 }
116
117 /**
118 * Resolves and checks the current command method name
119 *
120 * Note: The resulting command method name might not have the correct case, which isn't a problem because PHP is
121 * case insensitive regarding method names.
122 *
123 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchCommandException
124 * @return string Method name of the current command
125 */
126 protected function resolveCommandMethodName() {
127 $commandMethodName = $this->request->getControllerCommandName() . 'Command';
128 if (!is_callable(array($this, $commandMethodName))) {
129 throw new \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchCommandException('A command method "' . $commandMethodName . '()" does not exist in controller "' . get_class($this) . '".', 1300902143);
130 }
131 return $commandMethodName;
132 }
133
134 /**
135 * Initializes the arguments array of this controller by creating an empty argument object for each of the
136 * method arguments found in the designated command method.
137 *
138 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentTypeException
139 * @return void
140 */
141 protected function initializeCommandMethodArguments() {
142 $methodParameters = $this->reflectionService->getMethodParameters(get_class($this), $this->commandMethodName);
143 foreach ($methodParameters as $parameterName => $parameterInfo) {
144 $dataType = NULL;
145 if (isset($parameterInfo['type'])) {
146 $dataType = $parameterInfo['type'];
147 } elseif ($parameterInfo['array']) {
148 $dataType = 'array';
149 }
150 if ($dataType === NULL) {
151 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentTypeException('The argument type for parameter $' . $parameterName . ' of method ' . get_class($this) . '->' . $this->commandMethodName . '() could not be detected.', 1306755296);
152 }
153 $defaultValue = isset($parameterInfo['defaultValue']) ? $parameterInfo['defaultValue'] : NULL;
154 $this->arguments->addNewArgument($parameterName, $dataType, $parameterInfo['optional'] === FALSE, $defaultValue);
155 }
156 }
157
158 /**
159 * Maps arguments delivered by the request object to the local controller arguments.
160 *
161 * @return void
162 */
163 protected function mapRequestArgumentsToControllerArguments() {
164 /** @var Argument $argument */
165 foreach ($this->arguments as $argument) {
166 $argumentName = $argument->getName();
167 if ($this->request->hasArgument($argumentName)) {
168 $argument->setValue($this->request->getArgument($argumentName));
169 } elseif ($argument->isRequired()) {
170 $commandArgumentDefinition = $this->objectManager->get(CommandArgumentDefinition::class, $argumentName, TRUE, NULL);
171 $exception = new \TYPO3\CMS\Extbase\Mvc\Exception\CommandException('Required argument "' . $commandArgumentDefinition->getDashedName() . '" is not set.', 1306755520);
172 $this->forward('error', \TYPO3\CMS\Extbase\Command\HelpCommandController::class, array('exception' => $exception));
173 }
174 }
175 }
176
177 /**
178 * Forwards the request to another command and / or CommandController.
179 *
180 * Request is directly transferred to the other command / controller
181 * without the need for a new request.
182 *
183 * @param string $commandName
184 * @param string $controllerObjectName
185 * @param array $arguments
186 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
187 * @return void
188 */
189 protected function forward($commandName, $controllerObjectName = NULL, array $arguments = array()) {
190 $this->request->setDispatched(FALSE);
191 $this->request->setControllerCommandName($commandName);
192 if ($controllerObjectName !== NULL) {
193 $this->request->setControllerObjectName($controllerObjectName);
194 }
195 $this->request->setArguments($arguments);
196 $this->arguments->removeAll();
197 throw new \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException();
198 }
199
200 /**
201 * Calls the specified command method and passes the arguments.
202 *
203 * If the command returns a string, it is appended to the content in the
204 * response object. If the command doesn't return anything and a valid
205 * view exists, the view is rendered automatically.
206 *
207 * @return void
208 */
209 protected function callCommandMethod() {
210 $preparedArguments = array();
211 /** @var Argument $argument */
212 foreach ($this->arguments as $argument) {
213 $preparedArguments[] = $argument->getValue();
214 }
215 $originalRole = $this->ensureAdminRoleIfRequested();
216 $commandResult = call_user_func_array(array($this, $this->commandMethodName), $preparedArguments);
217 $this->restoreUserRole($originalRole);
218 if (is_string($commandResult) && $commandResult !== '') {
219 $this->response->appendContent($commandResult);
220 } elseif (is_object($commandResult) && method_exists($commandResult, '__toString')) {
221 $this->response->appendContent((string)$commandResult);
222 }
223 }
224
225 /**
226 * Set admin permissions for currently authenticated user if requested
227 * and returns the original state or NULL
228 *
229 * @return NULL|int
230 */
231 protected function ensureAdminRoleIfRequested() {
232 if (!$this->requestAdminPermissions || !$this->userAuthentication || !isset($this->userAuthentication->user['admin'])) {
233 return NULL;
234 }
235 $originalRole = $this->userAuthentication->user['admin'];
236 $this->userAuthentication->user['admin'] = 1;
237 return $originalRole;
238 }
239
240 /**
241 * Restores the original user role
242 *
243 * @param NULL|int $originalRole
244 */
245 protected function restoreUserRole($originalRole) {
246 if ($originalRole !== NULL) {
247 $this->userAuthentication->user['admin'] = $originalRole;
248 }
249 }
250
251 /**
252 * Outputs specified text to the console window
253 * You can specify arguments that will be passed to the text via sprintf
254 *
255 * @see http://www.php.net/sprintf
256 * @param string $text Text to output
257 * @param array $arguments Optional arguments to use for sprintf
258 * @return void
259 */
260 protected function output($text, array $arguments = array()) {
261 if ($arguments !== array()) {
262 $text = vsprintf($text, $arguments);
263 }
264 $this->response->appendContent($text);
265 }
266
267 /**
268 * Outputs specified text to the console window and appends a line break
269 *
270 * @param string $text Text to output
271 * @param array $arguments Optional arguments to use for sprintf
272 * @return void
273 * @see output()
274 */
275 protected function outputLine($text = '', array $arguments = array()) {
276 $this->output($text . PHP_EOL, $arguments);
277 }
278
279 /**
280 * Exits the CLI through the dispatcher
281 * An exit status code can be specified @see http://www.php.net/exit
282 *
283 * @param int $exitCode Exit code to return on exit
284 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
285 * @return void
286 */
287 protected function quit($exitCode = 0) {
288 $this->response->setExitCode($exitCode);
289 throw new \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException();
290 }
291
292 /**
293 * Sends the response and exits the CLI without any further code execution
294 * Should be used for commands that flush code caches.
295 *
296 * @param int $exitCode Exit code to return on exit
297 * @return void
298 */
299 protected function sendAndExit($exitCode = 0) {
300 $this->response->send();
301 die($exitCode);
302 }
303
304 }