[BUGFIX] Avoid clearing the page cache too often
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Controller / AbstractController.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Mvc\Controller;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2012 Extbase Team (http://forge.typo3.org/projects/typo3v4-mvc)
8 * Extbase is a backport of TYPO3 Flow. All credits go to the TYPO3 Flow team.
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /**
31 * An abstract base class for Controllers
32 *
33 * @api
34 */
35 abstract class AbstractController implements \TYPO3\CMS\Extbase\Mvc\Controller\ControllerInterface {
36
37 /**
38 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
39 */
40 protected $signalSlotDispatcher;
41
42 /**
43 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
44 */
45 protected $objectManager;
46
47 /**
48 * @var \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
49 */
50 protected $uriBuilder;
51
52 /**
53 * @var string Key of the extension this controller belongs to
54 */
55 protected $extensionName;
56
57 /**
58 * Contains the settings of the current extension
59 *
60 * @var array
61 * @api
62 */
63 protected $settings;
64
65 /**
66 * The current request.
67 *
68 * @var \TYPO3\CMS\Extbase\Mvc\Request
69 * @api
70 */
71 protected $request;
72
73 /**
74 * The response which will be returned by this action controller
75 *
76 * @var \TYPO3\CMS\Extbase\Mvc\Response
77 * @api
78 */
79 protected $response;
80
81 /**
82 * @var \TYPO3\CMS\Extbase\Property\Mapper
83 * @deprecated since Extbase 1.4.0, will be removed in Extbase 6.1
84 */
85 protected $deprecatedPropertyMapper;
86
87 /**
88 * @var \TYPO3\CMS\Extbase\Validation\ValidatorResolver
89 */
90 protected $validatorResolver;
91
92 /**
93 * @var \TYPO3\CMS\Extbase\Mvc\Controller\Arguments Arguments passed to the controller
94 */
95 protected $arguments;
96
97 /**
98 * The results of the mapping of request arguments to controller arguments
99 *
100 * @var \TYPO3\CMS\Extbase\Property\MappingResults
101 * @api
102 * @deprecated since Extbase 1.4.0, will be removed in Extbase 6.1
103 */
104 protected $argumentsMappingResults;
105
106 /**
107 * An array of supported request types. By default only web requests are supported.
108 * Modify or replace this array if your specific controller supports certain
109 * (additional) request types.
110 *
111 * @var array
112 */
113 protected $supportedRequestTypes = array('TYPO3\\CMS\\Extbase\\Mvc\\Request');
114
115 /**
116 * @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
117 * @api
118 */
119 protected $controllerContext;
120
121 /**
122 * The flash messages. Use $this->flashMessageContainer->add(...) to add a new Flash message.
123 *
124 * @var \TYPO3\CMS\Extbase\Mvc\Controller\FlashMessageContainer
125 * @api
126 */
127 protected $flashMessageContainer;
128
129 /**
130 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
131 */
132 protected $configurationManager;
133
134 /**
135 * Constructs the controller.
136 */
137 public function __construct() {
138 $className = get_class($this);
139 if (strpos($className, '\\') !== FALSE) {
140 $classNameParts = explode('\\', $className, 4);
141 // Skip vendor and product name for core classes
142 if (strpos($className, 'TYPO3\\CMS\\') === 0) {
143 $this->extensionName = $classNameParts[2];
144 } else {
145 $this->extensionName = $classNameParts[1];
146 }
147 } else {
148 list(, $this->extensionName) = explode('_', $className);
149 }
150 }
151
152 /**
153 * @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
154 * @return void
155 */
156 public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager) {
157 $this->configurationManager = $configurationManager;
158 $this->settings = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS);
159 }
160
161 /**
162 * Injects the property mapper
163 *
164 * @param \TYPO3\CMS\Extbase\Property\Mapper $deprecatedPropertyMapper The property mapper
165 * @return void
166 * @deprecated since Extbase 1.4.0, will be removed in Extbase 6.1
167 */
168 public function injectDeprecatedPropertyMapper(\TYPO3\CMS\Extbase\Property\Mapper $deprecatedPropertyMapper) {
169 $this->deprecatedPropertyMapper = $deprecatedPropertyMapper;
170 }
171
172 /**
173 * Injects the object manager
174 *
175 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
176 * @return void
177 */
178 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager) {
179 $this->objectManager = $objectManager;
180 $this->arguments = $this->objectManager->create('TYPO3\\CMS\\Extbase\\Mvc\\Controller\\Arguments');
181 }
182
183 /**
184 * Injects the validator resolver
185 *
186 * @param \TYPO3\CMS\Extbase\Validation\ValidatorResolver $validatorResolver
187 * @return void
188 */
189 public function injectValidatorResolver(\TYPO3\CMS\Extbase\Validation\ValidatorResolver $validatorResolver) {
190 $this->validatorResolver = $validatorResolver;
191 }
192
193 /**
194 * Injects the flash messages container
195 *
196 * @param \TYPO3\CMS\Extbase\Mvc\Controller\FlashMessageContainer $flashMessageContainer
197 * @return void
198 */
199 public function injectFlashMessageContainer(\TYPO3\CMS\Extbase\Mvc\Controller\FlashMessageContainer $flashMessageContainer) {
200 $this->flashMessageContainer = $flashMessageContainer;
201 }
202
203 /**
204 * Injects the signal slot dispatcher
205 *
206 * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher
207 */
208 public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher) {
209 $this->signalSlotDispatcher = $signalSlotDispatcher;
210 }
211
212 /**
213 * Checks if the current request type is supported by the controller.
214 *
215 * If your controller only supports certain request types, either
216 * replace / modify the supporteRequestTypes property or override this
217 * method.
218 *
219 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The current request
220 * @return boolean TRUE if this request type is supported, otherwise FALSE
221 * @api
222 */
223 public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request) {
224 foreach ($this->supportedRequestTypes as $supportedRequestType) {
225 if ($request instanceof $supportedRequestType) {
226 return TRUE;
227 }
228 }
229 return FALSE;
230 }
231
232 /**
233 * Processes a general request. The result can be returned by altering the given response.
234 *
235 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request object
236 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, modified by this handler
237 * @return void
238 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException if the controller doesn't support the current request type
239 * @api
240 */
241 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response) {
242 if (!$this->canProcessRequest($request)) {
243 throw new \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException(get_class($this) . ' does not support requests of type "' . get_class($request) . '". Supported types are: ' . implode(' ', $this->supportedRequestTypes), 1187701131);
244 }
245 $response->setRequest($request);
246 $this->request = $request;
247 $this->request->setDispatched(TRUE);
248 $this->response = $response;
249 $this->uriBuilder = $this->objectManager->create('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder');
250 $this->uriBuilder->setRequest($request);
251 $this->initializeControllerArgumentsBaseValidators();
252 $this->mapRequestArgumentsToControllerArguments();
253 $this->controllerContext = $this->buildControllerContext();
254 }
255
256 /**
257 * Initialize the controller context
258 *
259 * @return \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext ControllerContext to be passed to the view
260 * @api
261 */
262 protected function buildControllerContext() {
263 $controllerContext = $this->objectManager->create('TYPO3\\CMS\\Extbase\\Mvc\\Controller\\ControllerContext');
264 $controllerContext->setRequest($this->request);
265 $controllerContext->setResponse($this->response);
266 if ($this->arguments !== NULL) {
267 $controllerContext->setArguments($this->arguments);
268 }
269 if ($this->argumentsMappingResults !== NULL) {
270 $controllerContext->setArgumentsMappingResults($this->argumentsMappingResults);
271 }
272 $controllerContext->setUriBuilder($this->uriBuilder);
273 $controllerContext->setFlashMessageContainer($this->flashMessageContainer);
274 return $controllerContext;
275 }
276
277 /**
278 * Forwards the request to another action and / or controller.
279 *
280 * Request is directly transfered to the other action / controller
281 * without the need for a new request.
282 *
283 * @param string $actionName Name of the action to forward to
284 * @param string $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
285 * @param string $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
286 * @param array $arguments Arguments to pass to the target action
287 * @return void
288 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
289 * @see redirect()
290 * @api
291 */
292 public function forward($actionName, $controllerName = NULL, $extensionName = NULL, array $arguments = NULL) {
293 $this->request->setDispatched(FALSE);
294 $this->request->setControllerActionName($actionName);
295 if ($controllerName !== NULL) {
296 $this->request->setControllerName($controllerName);
297 }
298 if ($extensionName !== NULL) {
299 $this->request->setControllerExtensionName($extensionName);
300 }
301 if ($arguments !== NULL) {
302 $this->request->setArguments($arguments);
303 }
304 throw new \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException();
305 }
306
307 /**
308 * Redirects the request to another action and / or controller.
309 *
310 * Redirect will be sent to the client which then performs another request to the new URI.
311 *
312 * NOTE: This method only supports web requests and will thrown an exception
313 * if used with other request types.
314 *
315 * @param string $actionName Name of the action to forward to
316 * @param string $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
317 * @param string $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
318 * @param array $arguments Arguments to pass to the target action
319 * @param integer $pageUid Target page uid. If NULL, the current page uid is used
320 * @param integer $delay (optional) The delay in seconds. Default is no delay.
321 * @param integer $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
322 * @return void
323 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException If the request is not a web request
324 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
325 * @see forward()
326 * @api
327 */
328 protected function redirect($actionName, $controllerName = NULL, $extensionName = NULL, array $arguments = NULL, $pageUid = NULL, $delay = 0, $statusCode = 303) {
329 if (!$this->request instanceof \TYPO3\CMS\Extbase\Mvc\Web\Request) {
330 throw new \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539734);
331 }
332 if ($controllerName === NULL) {
333 $controllerName = $this->request->getControllerName();
334 }
335 $uri = $this->uriBuilder->reset()->setTargetPageUid($pageUid)->setCreateAbsoluteUri(TRUE)->uriFor($actionName, $arguments, $controllerName, $extensionName);
336 $this->redirectToUri($uri, $delay, $statusCode);
337 }
338
339 /**
340 * Redirects the web request to another uri.
341 *
342 * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
343 *
344 * @param mixed $uri A string representation of a URI
345 * @param integer $delay (optional) The delay in seconds. Default is no delay.
346 * @param integer $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
347 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException If the request is not a web request
348 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
349 * @api
350 */
351 protected function redirectToUri($uri, $delay = 0, $statusCode = 303) {
352 if (!$this->request instanceof \TYPO3\CMS\Extbase\Mvc\Web\Request) {
353 throw new \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539734);
354 }
355
356 $this->objectManager->get('TYPO3\CMS\Extbase\Service\CacheService')->clearCachesOfRegisteredPageIds();
357
358 $uri = $this->addBaseUriIfNecessary($uri);
359 $escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
360 $this->response->setContent('<html><head><meta http-equiv="refresh" content="' . intval($delay) . ';url=' . $escapedUri . '"/></head></html>');
361 $this->response->setStatus($statusCode);
362 $this->response->setHeader('Location', (string) $uri);
363 throw new \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException();
364 }
365
366 /**
367 * Adds the base uri if not already in place.
368 *
369 * @param string $uri The URI
370 * @return string
371 */
372 protected function addBaseUriIfNecessary($uri) {
373 return \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl((string) $uri);
374 }
375
376 /**
377 * Sends the specified HTTP status immediately.
378 *
379 * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
380 *
381 * @param integer $statusCode The HTTP status code
382 * @param string $statusMessage A custom HTTP status message
383 * @param string $content Body content which further explains the status
384 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException If the request is not a web request
385 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
386 * @api
387 */
388 public function throwStatus($statusCode, $statusMessage = NULL, $content = NULL) {
389 if (!$this->request instanceof \TYPO3\CMS\Extbase\Mvc\Web\Request) {
390 throw new \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException('throwStatus() only supports web requests.', 1220539739);
391 }
392 $this->response->setStatus($statusCode, $statusMessage);
393 if ($content === NULL) {
394 $content = $this->response->getStatus();
395 }
396 $this->response->setContent($content);
397 throw new \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException();
398 }
399
400 /**
401 * Collects the base validators which were defined for the data type of each
402 * controller argument and adds them to the argument's validator chain.
403 *
404 * @return void
405 */
406 public function initializeControllerArgumentsBaseValidators() {
407 foreach ($this->arguments as $argument) {
408 $validator = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
409 if ($validator !== NULL) {
410 $argument->setValidator($validator);
411 }
412 }
413 }
414
415 /**
416 * Maps arguments delivered by the request object to the local controller arguments.
417 *
418 * @throws Exception\RequiredArgumentMissingException
419 * @return void
420 */
421 protected function mapRequestArgumentsToControllerArguments() {
422 if ($this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
423 foreach ($this->arguments as $argument) {
424 $argumentName = $argument->getName();
425 if ($this->request->hasArgument($argumentName)) {
426 $argument->setValue($this->request->getArgument($argumentName));
427 } elseif ($argument->isRequired()) {
428 throw new \TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException('Required argument "' . $argumentName . '" is not set.', 1298012500);
429 }
430 }
431 } else {
432 // @deprecated since Extbase 1.4, will be removed in Extbase 6.1
433 $optionalPropertyNames = array();
434 $allPropertyNames = $this->arguments->getArgumentNames();
435 foreach ($allPropertyNames as $propertyName) {
436 if ($this->arguments[$propertyName]->isRequired() === FALSE) {
437 $optionalPropertyNames[] = $propertyName;
438 }
439 }
440 /** @var $validator ArgumentsValidator */
441 $validator = $this->objectManager->create('TYPO3\\CMS\\Extbase\\Mvc\\Controller\\ArgumentsValidator');
442 $this->deprecatedPropertyMapper->mapAndValidate($allPropertyNames, $this->request->getArguments(), $this->arguments, $optionalPropertyNames, $validator);
443 $this->argumentsMappingResults = $this->deprecatedPropertyMapper->getMappingResults();
444 }
445 }
446 }
447
448 ?>