[~TASK] Extbase: Refactored Dispatcher. Moved initialization of cache and reflection...
[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 */
35 abstract class Tx_Extbase_MVC_Controller_AbstractController implements Tx_Extbase_MVC_Controller_ControllerInterface {
36
37 /**
38 * @var Tx_Extbase_Object_ManagerInterface
39 */
40 protected $objectManager;
41
42 /**
43 * @var Tx_Extbase_MVC_Web_Routing_UriBuilder
44 */
45 protected $uriBuilder;
46
47 /**
48 * @var string Key of the extension this controller belongs to
49 */
50 protected $extensionName;
51
52 /**
53 * Contains the settings of the current extension
54 *
55 * @var array
56 * @api
57 */
58 protected $settings;
59
60 /**
61 * The current request.
62 *
63 * @var Tx_Extbase_MVC_Request
64 * @api
65 */
66 protected $request;
67
68 /**
69 * The response which will be returned by this action controller
70 *
71 * @var Tx_Extbase_MVC_Response
72 * @api
73 */
74 protected $response;
75
76 /**
77 * @var Tx_Extbase_Property_Mapper
78 */
79 protected $propertyMapper;
80
81 /**
82 * @var Tx_Extbase_Validation_ValidatorResolver
83 */
84 protected $validatorResolver;
85
86 /**
87 * @var Tx_Extbase_MVC_Controller_Arguments Arguments passed to the controller
88 */
89 protected $arguments;
90
91 /**
92 * The results of the mapping of request arguments to controller arguments
93 * @var Tx_Extbase_Property_MappingResults
94 * @api
95 */
96 protected $argumentsMappingResults;
97
98 /**
99 * An array of supported request types. By default only web requests are supported.
100 * Modify or replace this array if your specific controller supports certain
101 * (additional) request types.
102 * @var array
103 */
104 protected $supportedRequestTypes = array('Tx_Extbase_MVC_Request');
105
106 /**
107 * The flash messages. Use $this->flashMessages->add(...) to add a new Flash message.
108 *
109 * @var Tx_Extbase_MVC_Controller_FlashMessages
110 * @api
111 */
112 protected $flashMessages;
113
114 /**
115 * Constructs the controller.
116 */
117 public function __construct() {
118 $this->initializeObjects();
119 list(, $this->extensionName) = explode('_', get_class($this));
120 }
121
122 /**
123 * Initializes objects this class depends on
124 *
125 * @return void
126 */
127 protected function initializeObjects() {
128 $this->objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_Manager');
129 $this->arguments = t3lib_div::makeInstance('Tx_Extbase_MVC_Controller_Arguments');
130 $this->arguments->injectPersistenceManager(Tx_Extbase_Dispatcher::getPersistenceManager());
131 $this->arguments->injectQueryFactory(t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory'));
132 }
133
134 /**
135 * Injects the property mapper
136 *
137 * @param Tx_Extbase_Property_Mapper $propertyMapper The property mapper
138 * @return void
139 */
140 public function injectPropertyMapper(Tx_Extbase_Property_Mapper $propertyMapper) {
141 $this->propertyMapper = $propertyMapper;
142 }
143
144 /**
145 * Injects the settings of the extension.
146 *
147 * @param array $settings Settings container of the current extension
148 * @return void
149 */
150 public function injectSettings(array $settings) {
151 $this->settings = $settings;
152 }
153
154 /**
155 * Injects the object manager
156 *
157 * @param Tx_Extbase_Object_ManagerInterface $objectManager
158 * @return void
159 */
160 public function injectObjectManager(Tx_Extbase_Object_ManagerInterface $objectManager) {
161 $this->objectManager = $objectManager;
162 }
163
164 /**
165 * Injects the validator resolver
166 *
167 * @param Tx_Extbase_Validation_ValidatorResolver $validatorResolver
168 * @return void
169 */
170 public function injectValidatorResolver(Tx_Extbase_Validation_ValidatorResolver $validatorResolver) {
171 $this->validatorResolver = $validatorResolver;
172 }
173
174 /**
175 * Injects the flash messages container
176 *
177 * @param Tx_Extbase_MVC_Controller_FlashMessages $flashMessages
178 * @return void
179 */
180 public function injectFlashMessages(Tx_Extbase_MVC_Controller_FlashMessages $flashMessages) {
181 $this->flashMessages = $flashMessages;
182 }
183
184 /**
185 * Checks if the current request type is supported by the controller.
186 *
187 * If your controller only supports certain request types, either
188 * replace / modify the supporteRequestTypes property or override this
189 * method.
190 *
191 * @param Tx_Extbase_MVC_Request $request The current request
192 * @return boolean TRUE if this request type is supported, otherwise FALSE
193 * @api
194 */
195 public function canProcessRequest(Tx_Extbase_MVC_Request $request) {
196 foreach ($this->supportedRequestTypes as $supportedRequestType) {
197 if ($request instanceof $supportedRequestType) return TRUE;
198 }
199 return FALSE;
200 }
201
202 /**
203 * Processes a general request. The result can be returned by altering the given response.
204 *
205 * @param Tx_Extbase_MVC_Request $request The request object
206 * @param Tx_Extbase_MVC_Response $response The response, modified by this handler
207 * @return void
208 * @throws Tx_Extbase_MVC_Exception_UnsupportedRequestType if the controller doesn't support the current request type
209 * @api
210 */
211 public function processRequest(Tx_Extbase_MVC_Request $request, Tx_Extbase_MVC_Response $response) {
212 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);
213
214 $this->request = $request;
215 $this->request->setDispatched(TRUE);
216 $this->response = $response;
217
218 $this->uriBuilder = t3lib_div::makeInstance('Tx_Extbase_MVC_Web_Routing_UriBuilder');
219 $this->uriBuilder->setRequest($request);
220
221 $this->initializeControllerArgumentsBaseValidators();
222 $this->mapRequestArgumentsToControllerArguments();
223 }
224
225 /**
226 * Initialize the controller context
227 *
228 * @return Tx_Extbase_MVC_Controller_ControllerContext ControllerContext to be passed to the view
229 * @api
230 */
231 protected function buildControllerContext() {
232 $controllerContext = t3lib_div::makeInstance('Tx_Extbase_MVC_Controller_ControllerContext');
233 $controllerContext->setRequest($this->request);
234 $controllerContext->setResponse($this->response);
235 if ($this->arguments !== NULL) {
236 $controllerContext->setArguments($this->arguments);
237 }
238 if ($this->argumentsMappingResults !== NULL) {
239 $controllerContext->setArgumentsMappingResults($this->argumentsMappingResults);
240 }
241 $controllerContext->setUriBuilder($this->uriBuilder);
242 $controllerContext->setFlashMessages($this->flashMessages);
243 return $controllerContext;
244 }
245
246 /**
247 * Forwards the request to another controller.
248 *
249 * @param string $actionName Name of the action to forward to
250 * @param string $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
251 * @param string $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
252 * @param Tx_Extbase_MVC_Controller_Arguments $arguments Arguments to pass to the target action
253 * @return void
254 * @throws Tx_Extbase_MVC_Exception_StopAction
255 * @api
256 */
257 public function forward($actionName, $controllerName = NULL, $extensionName = NULL, array $arguments = NULL) {
258 $this->request->setDispatched(FALSE);
259 $this->request->setControllerActionName($actionName);
260 if ($controllerName !== NULL) $this->request->setControllerName($controllerName);
261 if ($extensionName !== NULL) $this->request->setControllerExtensionName($extensionName);
262 if ($arguments !== NULL) $this->request->setArguments($arguments);
263 throw new Tx_Extbase_MVC_Exception_StopAction();
264 }
265
266 /**
267 * Forwards the request to another action and / or controller.
268 *
269 * NOTE: This method only supports web requests and will thrown an exception
270 * if used with other request types.
271 *
272 * @param string $actionName Name of the action to forward to
273 * @param string $controllerName Unqualified object name of the controller to forward to. If not specified, the current controller is used.
274 * @param string $extensionName Name of the extension containing the controller to forward to. If not specified, the current extension is assumed.
275 * @param Tx_Extbase_MVC_Controller_Arguments $arguments Arguments to pass to the target action
276 * @param integer $pageUid Target page uid. If NULL, the current page uid is used
277 * @param integer $delay (optional) The delay in seconds. Default is no delay.
278 * @param integer $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other"
279 * @return void
280 * @throws Tx_Extbase_MVC_Exception_UnsupportedRequestType If the request is not a web request
281 * @throws Tx_Extbase_MVC_Exception_StopAction
282 * @api
283 */
284 protected function redirect($actionName, $controllerName = NULL, $extensionName = NULL, array $arguments = NULL, $pageUid = NULL, $delay = 0, $statusCode = 303) {
285 if (!$this->request instanceof Tx_Extbase_MVC_Web_Request) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType('redirect() only supports web requests.', 1220539734);
286
287 if ($controllerName === NULL) {
288 $controllerName = $this->request->getControllerName();
289 }
290 if ($pageUid === NULL && isset($GLOBALS['TSFE'])) {
291 $pageUid = $GLOBALS['TSFE']->id;
292 }
293
294 $uri = $this->uriBuilder
295 ->reset()
296 ->setTargetPageUid($pageUid)
297 ->uriFor($actionName, $arguments, $controllerName, $extensionName);
298 $this->redirectToURI($uri, $delay, $statusCode);
299 }
300
301 /**
302 * Redirects the web request to another uri.
303 *
304 * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
305 *
306 * @param mixed $uri A string representation of a URI
307 * @param integer $delay (optional) The delay in seconds. Default is no delay.
308 * @param integer $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other"
309 * @throws Tx_Extbase_MVC_Exception_UnsupportedRequestType If the request is not a web request
310 * @throws Tx_Extbase_MVC_Exception_StopAction
311 * @api
312 */
313 protected function redirectToURI($uri, $delay = 0, $statusCode = 303) {
314 if (!$this->request instanceof Tx_Extbase_MVC_Web_Request) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType('redirect() only supports web requests.', 1220539734);
315
316 $baseUri = $this->request->getBaseURI();
317
318 $uri = $baseUri . (string)$uri;
319 $escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
320 $this->response->setContent('<html><head><meta http-equiv="refresh" content="' . intval($delay) . ';url=' . $escapedUri . '"/></head></html>');
321 $this->response->setStatus($statusCode);
322 $this->response->setHeader('Location', (string)$uri);
323 throw new Tx_Extbase_MVC_Exception_StopAction();
324 }
325
326 /**
327 * Sends the specified HTTP status immediately.
328 *
329 * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
330 *
331 * @param integer $statusCode The HTTP status code
332 * @param string $statusMessage A custom HTTP status message
333 * @param string $content Body content which further explains the status
334 * @throws Tx_Extbase_MVC_Exception_UnsupportedRequestType If the request is not a web request
335 * @throws Tx_Extbase_MVC_Exception_StopAction
336 * @api
337 */
338 public function throwStatus($statusCode, $statusMessage = NULL, $content = NULL) {
339 if (!$this->request instanceof Tx_Extbase_MVC_Web_Request) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType('throwStatus() only supports web requests.', 1220539739);
340
341 $this->response->setStatus($statusCode, $statusMessage);
342 if ($content === NULL) $content = $this->response->getStatus();
343 $this->response->setContent($content);
344 throw new Tx_Extbase_MVC_Exception_StopAction();
345 }
346
347 /**
348 * Collects the base validators which were defined for the data type of each
349 * controller argument and adds them to the argument's validator chain.
350 *
351 * @return void
352 */
353 public function initializeControllerArgumentsBaseValidators() {
354 foreach ($this->arguments as $argument) {
355 $validator = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
356 if ($validator !== NULL) $argument->setValidator($validator);
357 }
358 }
359
360 /**
361 * Maps arguments delivered by the request object to the local controller arguments.
362 *
363 * @return void
364 */
365 protected function mapRequestArgumentsToControllerArguments() {
366 $optionalPropertyNames = array();
367 $allPropertyNames = $this->arguments->getArgumentNames();
368 foreach ($allPropertyNames as $propertyName) {
369 if ($this->arguments[$propertyName]->isRequired() === FALSE) $optionalPropertyNames[] = $propertyName;
370 }
371
372 $validator = t3lib_div::makeInstance('Tx_Extbase_MVC_Controller_ArgumentsValidator');
373 $this->propertyMapper->mapAndValidate($allPropertyNames, $this->request->getArguments(), $this->arguments, $optionalPropertyNames, $validator);
374
375 $this->argumentsMappingResults = $this->propertyMapper->getMappingResults();
376 }
377 }
378 ?>