[BUGFIX] AbstractMessage should have string, but integer is given
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Controller / AbstractController.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\Extbase\Configuration\ConfigurationManagerInterface;
18 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
19 use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
20 use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
21
22 /**
23 * An abstract base class for Controllers
24 *
25 * @api
26 */
27 abstract class AbstractController implements ControllerInterface
28 {
29 /**
30 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
31 */
32 protected $signalSlotDispatcher;
33
34 /**
35 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
36 */
37 protected $objectManager;
38
39 /**
40 * @var \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
41 */
42 protected $uriBuilder;
43
44 /**
45 * @var string Key of the extension this controller belongs to
46 */
47 protected $extensionName;
48
49 /**
50 * Contains the settings of the current extension
51 *
52 * @var array
53 * @api
54 */
55 protected $settings;
56
57 /**
58 * The current request.
59 *
60 * @var \TYPO3\CMS\Extbase\Mvc\RequestInterface
61 * @api
62 */
63 protected $request;
64
65 /**
66 * The response which will be returned by this action controller
67 *
68 * @var \TYPO3\CMS\Extbase\Mvc\ResponseInterface
69 * @api
70 */
71 protected $response;
72
73 /**
74 * @var \TYPO3\CMS\Extbase\Validation\ValidatorResolver
75 */
76 protected $validatorResolver;
77
78 /**
79 * @var \TYPO3\CMS\Extbase\Mvc\Controller\Arguments Arguments passed to the controller
80 */
81 protected $arguments;
82
83 /**
84 * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher
85 */
86 public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher)
87 {
88 $this->signalSlotDispatcher = $signalSlotDispatcher;
89 }
90
91 /**
92 * @param \TYPO3\CMS\Extbase\Validation\ValidatorResolver $validatorResolver
93 */
94 public function injectValidatorResolver(\TYPO3\CMS\Extbase\Validation\ValidatorResolver $validatorResolver)
95 {
96 $this->validatorResolver = $validatorResolver;
97 }
98
99 /**
100 * An array of supported request types. By default only web requests are supported.
101 * Modify or replace this array if your specific controller supports certain
102 * (additional) request types.
103 *
104 * @var array
105 */
106 protected $supportedRequestTypes = [\TYPO3\CMS\Extbase\Mvc\Request::class];
107
108 /**
109 * @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
110 * @api
111 */
112 protected $controllerContext;
113
114 /**
115 * @return ControllerContext
116 * @api
117 */
118 public function getControllerContext()
119 {
120 return $this->controllerContext;
121 }
122
123 /**
124 * @var ConfigurationManagerInterface
125 */
126 protected $configurationManager;
127
128 /**
129 * Constructs the controller.
130 */
131 public function __construct()
132 {
133 $className = get_class($this);
134 if (strpos($className, '\\') !== false) {
135 $classNameParts = explode('\\', $className, 4);
136 // Skip vendor and product name for core classes
137 if (strpos($className, 'TYPO3\\CMS\\') === 0) {
138 $this->extensionName = $classNameParts[2];
139 } else {
140 $this->extensionName = $classNameParts[1];
141 }
142 } else {
143 list(, $this->extensionName) = explode('_', $className);
144 }
145 }
146
147 /**
148 * @param ConfigurationManagerInterface $configurationManager
149 */
150 public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager)
151 {
152 $this->configurationManager = $configurationManager;
153 $this->settings = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS);
154 }
155
156 /**
157 * Injects the object manager
158 *
159 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
160 */
161 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
162 {
163 $this->objectManager = $objectManager;
164 $this->arguments = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Controller\Arguments::class);
165 }
166
167 /**
168 * Creates a Message object and adds it to the FlashMessageQueue.
169 *
170 * @param string $messageBody The message
171 * @param string $messageTitle Optional message title
172 * @param int $severity Optional severity, must be one of \TYPO3\CMS\Core\Messaging\FlashMessage constants
173 * @param bool $storeInSession Optional, defines whether the message should be stored in the session (default) or not
174 * @throws \InvalidArgumentException if the message body is no string
175 * @see \TYPO3\CMS\Core\Messaging\FlashMessage
176 * @api
177 */
178 public function addFlashMessage($messageBody, $messageTitle = '', $severity = \TYPO3\CMS\Core\Messaging\AbstractMessage::OK, $storeInSession = true)
179 {
180 if (!is_string($messageBody)) {
181 throw new \InvalidArgumentException('The message body must be of type string, "' . gettype($messageBody) . '" given.', 1243258395);
182 }
183 /* @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */
184 $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
185 \TYPO3\CMS\Core\Messaging\FlashMessage::class,
186 (string)$messageBody,
187 (string)$messageTitle,
188 $severity,
189 $storeInSession
190 );
191 $this->controllerContext->getFlashMessageQueue()->enqueue($flashMessage);
192 }
193
194 /**
195 * Checks if the current request type is supported by the controller.
196 *
197 * If your controller only supports certain request types, either
198 * replace / modify the supportedRequestTypes property or override this
199 * method.
200 *
201 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The current request
202 * @return bool TRUE if this request type is supported, otherwise FALSE
203 * @api
204 */
205 public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request)
206 {
207 foreach ($this->supportedRequestTypes as $supportedRequestType) {
208 if ($request instanceof $supportedRequestType) {
209 return true;
210 }
211 }
212 return false;
213 }
214
215 /**
216 * Processes a general request. The result can be returned by altering the given response.
217 *
218 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request object
219 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, modified by this handler
220 * @throws UnsupportedRequestTypeException if the controller doesn't support the current request type
221 * @api
222 */
223 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
224 {
225 if (!$this->canProcessRequest($request)) {
226 throw new UnsupportedRequestTypeException(get_class($this) . ' does not support requests of type "' . get_class($request) . '". Supported types are: ' . implode(' ', $this->supportedRequestTypes), 1187701132);
227 }
228 if ($response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response && $request instanceof WebRequest) {
229 $response->setRequest($request);
230 }
231 $this->request = $request;
232 $this->request->setDispatched(true);
233 $this->response = $response;
234 $this->uriBuilder = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::class);
235 $this->uriBuilder->setRequest($request);
236 $this->initializeControllerArgumentsBaseValidators();
237 $this->mapRequestArgumentsToControllerArguments();
238 $this->controllerContext = $this->buildControllerContext();
239 }
240
241 /**
242 * Initialize the controller context
243 *
244 * @return \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext ControllerContext to be passed to the view
245 * @api
246 */
247 protected function buildControllerContext()
248 {
249 /** @var $controllerContext \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext */
250 $controllerContext = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext::class);
251 $controllerContext->setRequest($this->request);
252 $controllerContext->setResponse($this->response);
253 if ($this->arguments !== null) {
254 $controllerContext->setArguments($this->arguments);
255 }
256 $controllerContext->setUriBuilder($this->uriBuilder);
257
258 return $controllerContext;
259 }
260
261 /**
262 * Forwards the request to another action and / or controller.
263 *
264 * Request is directly transferred to the other action / controller
265 * without the need for a new request.
266 *
267 * @param string $actionName Name of the action to forward to
268 * @param string $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
269 * @param string $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
270 * @param array $arguments Arguments to pass to the target action
271 * @throws StopActionException
272 * @see redirect()
273 * @api
274 */
275 public function forward($actionName, $controllerName = null, $extensionName = null, array $arguments = null)
276 {
277 $this->request->setDispatched(false);
278 if ($this->request instanceof WebRequest) {
279 $this->request->setControllerActionName($actionName);
280 if ($controllerName !== null) {
281 $this->request->setControllerName($controllerName);
282 }
283 if ($extensionName !== null) {
284 $this->request->setControllerExtensionName($extensionName);
285 }
286 }
287 if ($arguments !== null) {
288 $this->request->setArguments($arguments);
289 }
290 throw new StopActionException('forward', 1476045801);
291 }
292
293 /**
294 * Redirects the request to another action and / or controller.
295 *
296 * Redirect will be sent to the client which then performs another request to the new URI.
297 *
298 * NOTE: This method only supports web requests and will thrown an exception
299 * if used with other request types.
300 *
301 * @param string $actionName Name of the action to forward to
302 * @param string $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
303 * @param string $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
304 * @param array $arguments Arguments to pass to the target action
305 * @param int $pageUid Target page uid. If NULL, the current page uid is used
306 * @param int $delay (optional) The delay in seconds. Default is no delay.
307 * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
308 * @throws UnsupportedRequestTypeException If the request is not a web request
309 * @throws StopActionException
310 * @see forward()
311 * @api
312 */
313 protected function redirect($actionName, $controllerName = null, $extensionName = null, array $arguments = null, $pageUid = null, $delay = 0, $statusCode = 303)
314 {
315 if (!$this->request instanceof WebRequest) {
316 throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539734);
317 }
318 if ($controllerName === null) {
319 $controllerName = $this->request->getControllerName();
320 }
321 $this->uriBuilder->reset()->setTargetPageUid($pageUid)->setCreateAbsoluteUri(true);
322 if (\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SSL')) {
323 $this->uriBuilder->setAbsoluteUriScheme('https');
324 }
325 $uri = $this->uriBuilder->uriFor($actionName, $arguments, $controllerName, $extensionName);
326 $this->redirectToUri($uri, $delay, $statusCode);
327 }
328
329 /**
330 * Redirects the web request to another uri.
331 *
332 * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
333 *
334 * @param mixed $uri A string representation of a URI
335 * @param int $delay (optional) The delay in seconds. Default is no delay.
336 * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
337 * @throws UnsupportedRequestTypeException If the request is not a web request
338 * @throws StopActionException
339 * @api
340 */
341 protected function redirectToUri($uri, $delay = 0, $statusCode = 303)
342 {
343 if (!$this->request instanceof WebRequest) {
344 throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539735);
345 }
346
347 $this->objectManager->get(\TYPO3\CMS\Extbase\Service\CacheService::class)->clearCachesOfRegisteredPageIds();
348
349 $uri = $this->addBaseUriIfNecessary($uri);
350 $escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
351 $this->response->setContent('<html><head><meta http-equiv="refresh" content="' . (int)$delay . ';url=' . $escapedUri . '"/></head></html>');
352 if ($this->response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
353 $this->response->setStatus($statusCode);
354 $this->response->setHeader('Location', (string)$uri);
355 }
356 throw new StopActionException('redirectToUri', 1476045828);
357 }
358
359 /**
360 * Adds the base uri if not already in place.
361 *
362 * @param string $uri The URI
363 * @return string
364 */
365 protected function addBaseUriIfNecessary($uri)
366 {
367 return \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl((string)$uri);
368 }
369
370 /**
371 * Sends the specified HTTP status immediately.
372 *
373 * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
374 *
375 * @param int $statusCode The HTTP status code
376 * @param string $statusMessage A custom HTTP status message
377 * @param string $content Body content which further explains the status
378 * @throws UnsupportedRequestTypeException If the request is not a web request
379 * @throws StopActionException
380 * @api
381 */
382 public function throwStatus($statusCode, $statusMessage = null, $content = null)
383 {
384 if (!$this->request instanceof WebRequest) {
385 throw new UnsupportedRequestTypeException('throwStatus() only supports web requests.', 1220539739);
386 }
387 if ($this->response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
388 $this->response->setStatus($statusCode, $statusMessage);
389 if ($content === null) {
390 $content = $this->response->getStatus();
391 }
392 }
393 $this->response->setContent($content);
394 throw new StopActionException('throwStatus', 1476045871);
395 }
396
397 /**
398 * Collects the base validators which were defined for the data type of each
399 * controller argument and adds them to the argument's validator chain.
400 */
401 public function initializeControllerArgumentsBaseValidators()
402 {
403 /** @var \TYPO3\CMS\Extbase\Mvc\Controller\Argument $argument */
404 foreach ($this->arguments as $argument) {
405 $validator = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
406 if ($validator !== null) {
407 $argument->setValidator($validator);
408 }
409 }
410 }
411
412 /**
413 * Maps arguments delivered by the request object to the local controller arguments.
414 *
415 * @throws Exception\RequiredArgumentMissingException
416 */
417 protected function mapRequestArgumentsToControllerArguments()
418 {
419 /** @var \TYPO3\CMS\Extbase\Mvc\Controller\Argument $argument */
420 foreach ($this->arguments as $argument) {
421 $argumentName = $argument->getName();
422 if ($this->request->hasArgument($argumentName)) {
423 $argument->setValue($this->request->getArgument($argumentName));
424 } elseif ($argument->isRequired()) {
425 throw new \TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException('Required argument "' . $argumentName . '" is not set for ' . $this->request->getControllerObjectName() . '->' . $this->request->getControllerActionName() . '.', 1298012500);
426 }
427 }
428 }
429 }