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