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