b4c80917228e2114e2eca05745f950ebf5337c57
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / MVC / Controller / AbstractController.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
6 * All rights reserved
7 *
8 * This class is a backport of the corresponding class of FLOW3.
9 * All credits go to the v5 team.
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 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * An abstract base class for Controllers
30 *
31 * @package Extbase
32 * @subpackage MVC\Controller
33 * @version $ID:$
34 * @api
35 */
36 abstract class Tx_Extbase_MVC_Controller_AbstractController implements Tx_Extbase_MVC_Controller_ControllerInterface {
37
38 /**
39 * @var Tx_Extbase_Object_ManagerInterface
40 */
41 protected $objectManager;
42
43 /**
44 * @var Tx_Extbase_MVC_Web_Routing_UriBuilder
45 */
46 protected $uriBuilder;
47
48 /**
49 * @var string Key of the extension this controller belongs to
50 */
51 protected $extensionName;
52
53 /**
54 * Contains the settings of the current extension
55 *
56 * @var array
57 * @api
58 */
59 protected $settings;
60
61 /**
62 * The current request.
63 *
64 * @var Tx_Extbase_MVC_Request
65 * @api
66 */
67 protected $request;
68
69 /**
70 * The response which will be returned by this action controller
71 *
72 * @var Tx_Extbase_MVC_Response
73 * @api
74 */
75 protected $response;
76
77 /**
78 * @var Tx_Extbase_Property_Mapper
79 */
80 protected $propertyMapper;
81
82 /**
83 * @var Tx_Extbase_Validation_ValidatorResolver
84 */
85 protected $validatorResolver;
86
87 /**
88 * @var Tx_Extbase_MVC_Controller_Arguments Arguments passed to the controller
89 */
90 protected $arguments;
91
92 /**
93 * The results of the mapping of request arguments to controller arguments
94 * @var Tx_Extbase_Property_MappingResults
95 * @api
96 */
97 protected $argumentsMappingResults;
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 * @var array
104 */
105 protected $supportedRequestTypes = array('Tx_Extbase_MVC_Request');
106
107 /**
108 * The flash messages. DEPRECATED. Use $this->flashMessageContainer instead.
109 *
110 * @var Tx_Extbase_MVC_Controller_FlashMessages
111 * @deprecated
112 */
113 protected $flashMessages;
114
115 /**
116 * The flash messages. Use $this->flashMessageContainer->add(...) to add a new Flash message.
117 *
118 * @var Tx_Extbase_MVC_Controller_FlashMessages
119 * @api
120 */
121 protected $flashMessageContainer;
122
123 /**
124 * Constructs the controller.
125 */
126 public function __construct() {
127 $this->initializeObjects();
128 list(, $this->extensionName) = explode('_', get_class($this));
129 }
130
131 /**
132 * Initializes objects this class depends on
133 *
134 * @return void
135 */
136 protected function initializeObjects() {
137 $this->objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_Manager');
138 $this->arguments = t3lib_div::makeInstance('Tx_Extbase_MVC_Controller_Arguments');
139 $this->arguments->injectPersistenceManager(Tx_Extbase_Dispatcher::getPersistenceManager());
140 $this->arguments->injectQueryFactory(t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory'));
141 }
142
143 /**
144 * Injects the property mapper
145 *
146 * @param Tx_Extbase_Property_Mapper $propertyMapper The property mapper
147 * @return void
148 */
149 public function injectPropertyMapper(Tx_Extbase_Property_Mapper $propertyMapper) {
150 $this->propertyMapper = $propertyMapper;
151 }
152
153 /**
154 * Injects the settings of the extension.
155 *
156 * @param array $settings Settings container of the current extension
157 * @return void
158 */
159 public function injectSettings(array $settings) {
160 $this->settings = $settings;
161 }
162
163 /**
164 * Injects the object manager
165 *
166 * @param Tx_Extbase_Object_ManagerInterface $objectManager
167 * @return void
168 */
169 public function injectObjectManager(Tx_Extbase_Object_ManagerInterface $objectManager) {
170 $this->objectManager = $objectManager;
171 }
172
173 /**
174 * Injects the validator resolver
175 *
176 * @param Tx_Extbase_Validation_ValidatorResolver $validatorResolver
177 * @return void
178 */
179 public function injectValidatorResolver(Tx_Extbase_Validation_ValidatorResolver $validatorResolver) {
180 $this->validatorResolver = $validatorResolver;
181 }
182
183 /**
184 * Injects the flash messages container
185 *
186 * @param Tx_Extbase_MVC_Controller_FlashMessages $flashMessages
187 * @return void
188 */
189 public function injectFlashMessageContainer(Tx_Extbase_MVC_Controller_FlashMessages $flashMessageContainer) {
190 $this->flashMessageContainer = $flashMessageContainer;
191 $this->flashMessages = $flashMessageContainer; // deprecated, but should still work.
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 supporteRequestTypes property or override this
199 * method.
200 *
201 * @param Tx_Extbase_MVC_Request $request The current request
202 * @return boolean TRUE if this request type is supported, otherwise FALSE
203 * @api
204 */
205 public function canProcessRequest(Tx_Extbase_MVC_Request $request) {
206 foreach ($this->supportedRequestTypes as $supportedRequestType) {
207 if ($request instanceof $supportedRequestType) return TRUE;
208 }
209 return FALSE;
210 }
211
212 /**
213 * Processes a general request. The result can be returned by altering the given response.
214 *
215 * @param Tx_Extbase_MVC_Request $request The request object
216 * @param Tx_Extbase_MVC_Response $response The response, modified by this handler
217 * @return void
218 * @throws Tx_Extbase_MVC_Exception_UnsupportedRequestType if the controller doesn't support the current request type
219 * @api
220 */
221 public function processRequest(Tx_Extbase_MVC_Request $request, Tx_Extbase_MVC_Response $response) {
222 if (!$this->canProcessRequest($request)) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType(get_class($this) . ' does not support requests of type "' . get_class($request) . '". Supported types are: ' . implode(' ', $this->supportedRequestTypes) , 1187701131);
223
224 $this->request = $request;
225 $this->request->setDispatched(TRUE);
226 $this->response = $response;
227
228 $this->uriBuilder = t3lib_div::makeInstance('Tx_Extbase_MVC_Web_Routing_UriBuilder');
229 $this->uriBuilder->setRequest($request);
230
231 $this->initializeControllerArgumentsBaseValidators();
232 $this->mapRequestArgumentsToControllerArguments();
233 }
234
235 /**
236 * Initialize the controller context
237 *
238 * @return Tx_Extbase_MVC_Controller_ControllerContext ControllerContext to be passed to the view
239 * @api
240 */
241 protected function buildControllerContext() {
242 $controllerContext = t3lib_div::makeInstance('Tx_Extbase_MVC_Controller_ControllerContext');
243 $controllerContext->setRequest($this->request);
244 $controllerContext->setResponse($this->response);
245 if ($this->arguments !== NULL) {
246 $controllerContext->setArguments($this->arguments);
247 }
248 if ($this->argumentsMappingResults !== NULL) {
249 $controllerContext->setArgumentsMappingResults($this->argumentsMappingResults);
250 }
251 $controllerContext->setUriBuilder($this->uriBuilder);
252 $controllerContext->setFlashMessageContainer($this->flashMessageContainer);
253 return $controllerContext;
254 }
255
256 /**
257 * Forwards the request to another controller.
258 *
259 * @param string $actionName Name of the action to forward to
260 * @param string $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
261 * @param string $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
262 * @param Tx_Extbase_MVC_Controller_Arguments $arguments Arguments to pass to the target action
263 * @return void
264 * @throws Tx_Extbase_MVC_Exception_StopAction
265 * @api
266 */
267 public function forward($actionName, $controllerName = NULL, $extensionName = NULL, array $arguments = NULL) {
268 $this->request->setDispatched(FALSE);
269 $this->request->setControllerActionName($actionName);
270 if ($controllerName !== NULL) $this->request->setControllerName($controllerName);
271 if ($extensionName !== NULL) $this->request->setControllerExtensionName($extensionName);
272 if ($arguments !== NULL) $this->request->setArguments($arguments);
273 throw new Tx_Extbase_MVC_Exception_StopAction();
274 }
275
276 /**
277 * Forwards the request to another action and / or controller.
278 *
279 * NOTE: This method only supports web requests and will thrown an exception
280 * if used with other request types.
281 *
282 * @param string $actionName Name of the action to forward to
283 * @param string $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
284 * @param string $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
285 * @param Tx_Extbase_MVC_Controller_Arguments $arguments Arguments to pass to the target action
286 * @param integer $pageUid Target page uid. If NULL, the current page uid is used
287 * @param integer $delay (optional) The delay in seconds. Default is no delay.
288 * @param integer $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other"
289 * @return void
290 * @throws Tx_Extbase_MVC_Exception_UnsupportedRequestType If the request is not a web request
291 * @throws Tx_Extbase_MVC_Exception_StopAction
292 * @api
293 */
294 protected function redirect($actionName, $controllerName = NULL, $extensionName = NULL, array $arguments = NULL, $pageUid = NULL, $delay = 0, $statusCode = 303) {
295 if (!$this->request instanceof Tx_Extbase_MVC_Web_Request) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType('redirect() only supports web requests.', 1220539734);
296
297 if ($controllerName === NULL) {
298 $controllerName = $this->request->getControllerName();
299 }
300 if ($pageUid === NULL && isset($GLOBALS['TSFE'])) {
301 $pageUid = $GLOBALS['TSFE']->id;
302 }
303
304 $uri = $this->uriBuilder
305 ->reset()
306 ->setTargetPageUid($pageUid)
307 ->uriFor($actionName, $arguments, $controllerName, $extensionName);
308 $this->redirectToURI($uri, $delay, $statusCode);
309 }
310
311 /**
312 * Redirects the web request to another uri.
313 *
314 * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
315 *
316 * @param mixed $uri A string representation of a URI
317 * @param integer $delay (optional) The delay in seconds. Default is no delay.
318 * @param integer $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other"
319 * @throws Tx_Extbase_MVC_Exception_UnsupportedRequestType If the request is not a web request
320 * @throws Tx_Extbase_MVC_Exception_StopAction
321 * @api
322 */
323 protected function redirectToURI($uri, $delay = 0, $statusCode = 303) {
324 if (!$this->request instanceof Tx_Extbase_MVC_Web_Request) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType('redirect() only supports web requests.', 1220539734);
325
326 $uri = $this->addBaseUriIfNecessary($uri);
327 $escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
328 $this->response->setContent('<html><head><meta http-equiv="refresh" content="' . intval($delay) . ';url=' . $escapedUri . '"/></head></html>');
329 $this->response->setStatus($statusCode);
330 $this->response->setHeader('Location', (string)$uri);
331 throw new Tx_Extbase_MVC_Exception_StopAction();
332 }
333
334 /**
335 * Adds the base uri if not already in place.
336 *
337 * @param string $uri The URI
338 * @return void
339 */
340 protected function addBaseUriIfNecessary($uri) {
341 $baseUri = $this->request->getBaseURI();
342 if(stripos($uri, $baseUri) !== 0) {
343 $uri = $baseUri . (string)$uri;
344 }
345 return $uri;
346 }
347
348 /**
349 * Sends the specified HTTP status immediately.
350 *
351 * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
352 *
353 * @param integer $statusCode The HTTP status code
354 * @param string $statusMessage A custom HTTP status message
355 * @param string $content Body content which further explains the status
356 * @throws Tx_Extbase_MVC_Exception_UnsupportedRequestType If the request is not a web request
357 * @throws Tx_Extbase_MVC_Exception_StopAction
358 * @api
359 */
360 public function throwStatus($statusCode, $statusMessage = NULL, $content = NULL) {
361 if (!$this->request instanceof Tx_Extbase_MVC_Web_Request) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType('throwStatus() only supports web requests.', 1220539739);
362
363 $this->response->setStatus($statusCode, $statusMessage);
364 if ($content === NULL) $content = $this->response->getStatus();
365 $this->response->setContent($content);
366 throw new Tx_Extbase_MVC_Exception_StopAction();
367 }
368
369 /**
370 * Collects the base validators which were defined for the data type of each
371 * controller argument and adds them to the argument's validator chain.
372 *
373 * @return void
374 */
375 public function initializeControllerArgumentsBaseValidators() {
376 foreach ($this->arguments as $argument) {
377 $validator = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
378 if ($validator !== NULL) $argument->setValidator($validator);
379 }
380 }
381
382 /**
383 * Maps arguments delivered by the request object to the local controller arguments.
384 *
385 * @return void
386 */
387 protected function mapRequestArgumentsToControllerArguments() {
388 $optionalPropertyNames = array();
389 $allPropertyNames = $this->arguments->getArgumentNames();
390 foreach ($allPropertyNames as $propertyName) {
391 if ($this->arguments[$propertyName]->isRequired() === FALSE) $optionalPropertyNames[] = $propertyName;
392 }
393
394 $validator = t3lib_div::makeInstance('Tx_Extbase_MVC_Controller_ArgumentsValidator');
395 $this->propertyMapper->mapAndValidate($allPropertyNames, $this->request->getArguments(), $this->arguments, $optionalPropertyNames, $validator);
396
397 $this->argumentsMappingResults = $this->propertyMapper->getMappingResults();
398 }
399 }
400 ?>