[TASK] Improve error message in NotFoundView to identify source
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Controller / ActionController.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Mvc\Controller;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2013 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 * A multi action controller. This is by far the most common base class for Controllers.
32 *
33 * @api
34 */
35 class ActionController extends \TYPO3\CMS\Extbase\Mvc\Controller\AbstractController {
36
37 /**
38 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
39 */
40 protected $reflectionService;
41
42 /**
43 * @var \TYPO3\CMS\Extbase\Service\CacheService
44 */
45 protected $cacheService;
46
47 /**
48 * The current view, as resolved by resolveView()
49 *
50 * @var \TYPO3\CMS\Extbase\Mvc\View\ViewInterface
51 * @api
52 */
53 protected $view = NULL;
54
55 /**
56 * Pattern after which the view object name is built if no Fluid template
57 * is found.
58 *
59 * @var string
60 * @api
61 */
62 protected $viewObjectNamePattern = '@vendor\@extension\View\@controller\@action@format';
63
64 /**
65 * @var string
66 * @api
67 * @deprecated since Extbase 6.2, will be removed two versions later
68 */
69 protected $deprecatedViewObjectNamePattern = 'Tx_@extension_View_@controller_@action@format';
70
71 /**
72 * A list of formats and object names of the views which should render them.
73 *
74 * Example:
75 *
76 * array('html' => 'Tx_MyExtension_View_MyHtmlView', 'json' => 'F3...
77 *
78 * @var array
79 */
80 protected $viewFormatToObjectNameMap = array();
81
82 /**
83 * The default view object to use if none of the resolved views can render
84 * a response for the current request.
85 *
86 * @var string
87 * @api
88 */
89 protected $defaultViewObjectName = 'TYPO3\\CMS\\Fluid\\View\\TemplateView';
90
91 /**
92 * Name of the action method
93 *
94 * @var string
95 * @api
96 */
97 protected $actionMethodName = 'indexAction';
98
99 /**
100 * Name of the special error action method which is called in case of errors
101 *
102 * @var string
103 * @api
104 */
105 protected $errorMethodName = 'errorAction';
106
107 /**
108 * @var \TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService
109 * @api
110 */
111 protected $mvcPropertyMappingConfigurationService;
112
113 /**
114 * @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
115 * @return void
116 */
117 public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService) {
118 $this->reflectionService = $reflectionService;
119 }
120
121 /**
122 * @param \TYPO3\CMS\Extbase\Service\CacheService $cacheService
123 * @return void
124 */
125 public function injectCacheService(\TYPO3\CMS\Extbase\Service\CacheService $cacheService) {
126 $this->cacheService = $cacheService;
127 }
128
129 /**
130 * @param \TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService $mvcPropertyMappingConfigurationService
131 */
132 public function injectMvcPropertyMappingConfigurationService(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService $mvcPropertyMappingConfigurationService) {
133 $this->mvcPropertyMappingConfigurationService = $mvcPropertyMappingConfigurationService;
134 }
135
136 /**
137 * Checks if the current request type is supported by the controller.
138 *
139 * If your controller only supports certain request types, either
140 * replace / modify the supporteRequestTypes property or override this
141 * method.
142 *
143 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The current request
144 * @return boolean TRUE if this request type is supported, otherwise FALSE
145 */
146 public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request) {
147 return parent::canProcessRequest($request);
148 }
149
150 /**
151 * Handles a request. The result output is returned by altering the given response.
152 *
153 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request object
154 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, modified by this handler
155 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
156 * @return void
157 */
158 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response) {
159 if (!$this->canProcessRequest($request)) {
160 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);
161 }
162 if ($response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
163 $response->setRequest($request);
164 }
165 $this->request = $request;
166 $this->request->setDispatched(TRUE);
167 $this->response = $response;
168 $this->uriBuilder = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder');
169 $this->uriBuilder->setRequest($request);
170 $this->actionMethodName = $this->resolveActionMethodName();
171 $this->initializeActionMethodArguments();
172 $this->initializeActionMethodValidators();
173 $this->mvcPropertyMappingConfigurationService->initializePropertyMappingConfigurationFromRequest($request, $this->arguments);
174 $this->initializeAction();
175 $actionInitializationMethodName = 'initialize' . ucfirst($this->actionMethodName);
176 if (method_exists($this, $actionInitializationMethodName)) {
177 call_user_func(array($this, $actionInitializationMethodName));
178 }
179 $this->mapRequestArgumentsToControllerArguments();
180 $this->checkRequestHash();
181 $this->controllerContext = $this->buildControllerContext();
182 $this->view = $this->resolveView();
183 if ($this->view !== NULL) {
184 $this->initializeView($this->view);
185 }
186 $this->callActionMethod();
187 }
188
189 /**
190 * Implementation of the arguments initilization in the action controller:
191 * Automatically registers arguments of the current action
192 *
193 * Don't override this method - use initializeAction() instead.
194 *
195 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentTypeException
196 * @return void
197 * @see initializeArguments()
198 */
199 protected function initializeActionMethodArguments() {
200 $methodParameters = $this->reflectionService->getMethodParameters(get_class($this), $this->actionMethodName);
201 foreach ($methodParameters as $parameterName => $parameterInfo) {
202 $dataType = NULL;
203 if (isset($parameterInfo['type'])) {
204 $dataType = $parameterInfo['type'];
205 } elseif ($parameterInfo['array']) {
206 $dataType = 'array';
207 }
208 if ($dataType === NULL) {
209 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentTypeException('The argument type for parameter $' . $parameterName . ' of method ' . get_class($this) . '->' . $this->actionMethodName . '() could not be detected.', 1253175643);
210 }
211 $defaultValue = isset($parameterInfo['defaultValue']) ? $parameterInfo['defaultValue'] : NULL;
212 $this->arguments->addNewArgument($parameterName, $dataType, $parameterInfo['optional'] === FALSE, $defaultValue);
213 }
214 }
215
216 /**
217 * Adds the needed valiators to the Arguments:
218 * - Validators checking the data type from the @param annotation
219 * - Custom validators specified with @validate.
220 *
221 * In case @dontvalidate is NOT set for an argument, the following two
222 * validators are also added:
223 * - Model-based validators (@validate annotations in the model)
224 * - Custom model validator classes
225 *
226 * @return void
227 */
228 protected function initializeActionMethodValidators() {
229 // TODO: still needs to be modified
230 $parameterValidators = $this->validatorResolver->buildMethodArgumentsValidatorConjunctions(get_class($this), $this->actionMethodName);
231 $dontValidateAnnotations = array();
232 if (!$this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
233 // If the rewritten property mapper is *enabled*, we do not support @dontvalidate annotation, thus $dontValidateAnnotations stays empty.
234 $methodTagsValues = $this->reflectionService->getMethodTagsValues(get_class($this), $this->actionMethodName);
235 if (isset($methodTagsValues['dontvalidate'])) {
236 $dontValidateAnnotations = $methodTagsValues['dontvalidate'];
237 }
238 }
239 foreach ($this->arguments as $argument) {
240 $validator = $parameterValidators[$argument->getName()];
241 if (array_search('$' . $argument->getName(), $dontValidateAnnotations) === FALSE) {
242 $baseValidatorConjunction = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
243 if ($baseValidatorConjunction !== NULL) {
244 $validator->addValidator($baseValidatorConjunction);
245 }
246 }
247 $argument->setValidator($validator);
248 }
249 }
250
251 /**
252 * Resolves and checks the current action method name
253 *
254 * @return string Method name of the current action
255 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchActionException if the action specified in the request object does not exist (and if there's no default action either).
256 */
257 protected function resolveActionMethodName() {
258 $actionMethodName = $this->request->getControllerActionName() . 'Action';
259 if (!method_exists($this, $actionMethodName)) {
260 throw new \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchActionException('An action "' . $actionMethodName . '" does not exist in controller "' . get_class($this) . '".', 1186669086);
261 }
262 return $actionMethodName;
263 }
264
265 /**
266 * Calls the specified action method and passes the arguments.
267 *
268 * If the action returns a string, it is appended to the content in the
269 * response object. If the action doesn't return anything and a valid
270 * view exists, the view is rendered automatically.
271 *
272 * @return void
273 * @api
274 */
275 protected function callActionMethod() {
276 if ($this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
277 // enabled since Extbase 1.4.0.
278 $preparedArguments = array();
279 foreach ($this->arguments as $argument) {
280 $preparedArguments[] = $argument->getValue();
281 }
282 $validationResult = $this->arguments->getValidationResults();
283 if (!$validationResult->hasErrors()) {
284 $this->signalSlotDispatcher->dispatch(__CLASS__, 'beforeCallActionMethod', array('controllerName' => get_class($this), 'actionMethodName' => $this->actionMethodName, 'preparedArguments' => $preparedArguments));
285 $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
286 } else {
287 $methodTagsValues = $this->reflectionService->getMethodTagsValues(get_class($this), $this->actionMethodName);
288 $ignoreValidationAnnotations = array();
289 if (isset($methodTagsValues['ignorevalidation'])) {
290 $ignoreValidationAnnotations = $methodTagsValues['ignorevalidation'];
291 }
292 // if there exists more errors than in ignoreValidationAnnotations_=> call error method
293 // else => call action method
294 $shouldCallActionMethod = TRUE;
295 foreach ($validationResult->getSubResults() as $argumentName => $subValidationResult) {
296 if (!$subValidationResult->hasErrors()) {
297 continue;
298 }
299 if (array_search('$' . $argumentName, $ignoreValidationAnnotations) !== FALSE) {
300 continue;
301 }
302 $shouldCallActionMethod = FALSE;
303 }
304 if ($shouldCallActionMethod) {
305 $this->signalSlotDispatcher->dispatch(__CLASS__, 'beforeCallActionMethod', array('controllerName' => get_class($this), 'actionMethodName' => $this->actionMethodName, 'preparedArguments' => $preparedArguments));
306 $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
307 } else {
308 $actionResult = call_user_func(array($this, $this->errorMethodName));
309 }
310 }
311 } else {
312 // @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
313 $preparedArguments = array();
314 foreach ($this->arguments as $argument) {
315 $preparedArguments[] = $argument->getValue();
316 }
317 if ($this->argumentsMappingResults->hasErrors()) {
318 $actionResult = call_user_func(array($this, $this->errorMethodName));
319 } else {
320 $this->signalSlotDispatcher->dispatch(__CLASS__, 'beforeCallActionMethod', array('controllerName' => get_class($this), 'actionMethodName' => $this->actionMethodName, 'preparedArguments' => $preparedArguments));
321 $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
322 }
323 }
324 if ($actionResult === NULL && $this->view instanceof \TYPO3\CMS\Extbase\Mvc\View\ViewInterface) {
325 $this->response->appendContent($this->view->render());
326 } elseif (is_string($actionResult) && strlen($actionResult) > 0) {
327 $this->response->appendContent($actionResult);
328 } elseif (is_object($actionResult) && method_exists($actionResult, '__toString')) {
329 $this->response->appendContent((string) $actionResult);
330 }
331 }
332
333 /**
334 * Prepares a view for the current action and stores it in $this->view.
335 * By default, this method tries to locate a view with a name matching
336 * the current action.
337 *
338 * @return string
339 * @api
340 */
341 protected function resolveView() {
342 $viewObjectName = $this->resolveViewObjectName();
343 if ($viewObjectName !== FALSE) {
344 /** @var $view \TYPO3\CMS\Extbase\Mvc\View\ViewInterface */
345 $view = $this->objectManager->get($viewObjectName);
346 $this->setViewConfiguration($view);
347 if ($view->canRender($this->controllerContext) === FALSE) {
348 unset($view);
349 }
350 }
351 if (!isset($view) && $this->defaultViewObjectName != '') {
352 /** @var $view \TYPO3\CMS\Extbase\Mvc\View\ViewInterface */
353 $view = $this->objectManager->get($this->defaultViewObjectName);
354 $this->setViewConfiguration($view);
355 if ($view->canRender($this->controllerContext) === FALSE) {
356 unset($view);
357 }
358 }
359 if (!isset($view)) {
360 $view = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\View\\NotFoundView');
361 $view->assign('errorMessage', 'No template was found. View could not be resolved for action "'
362 . $this->request->getControllerActionName() . '" in class "' . $this->request->getControllerObjectName() . '"');
363 }
364 $view->setControllerContext($this->controllerContext);
365 if (method_exists($view, 'injectSettings')) {
366 $view->injectSettings($this->settings);
367 }
368 $view->initializeView();
369 // In FLOW3, solved through Object Lifecycle methods, we need to call it explicitely
370 $view->assign('settings', $this->settings);
371 // same with settings injection.
372 return $view;
373 }
374
375 /**
376 * @param \TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view
377 * @return void
378 */
379 protected function setViewConfiguration(\TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view) {
380 // Template Path Override
381 $extbaseFrameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
382 if (isset($extbaseFrameworkConfiguration['view']['templateRootPath']) && strlen($extbaseFrameworkConfiguration['view']['templateRootPath']) > 0 && method_exists($view, 'setTemplateRootPath')) {
383 $view->setTemplateRootPath(\TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($extbaseFrameworkConfiguration['view']['templateRootPath']));
384 }
385 if (isset($extbaseFrameworkConfiguration['view']['layoutRootPath']) && strlen($extbaseFrameworkConfiguration['view']['layoutRootPath']) > 0 && method_exists($view, 'setLayoutRootPath')) {
386 $view->setLayoutRootPath(\TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($extbaseFrameworkConfiguration['view']['layoutRootPath']));
387 }
388 if (isset($extbaseFrameworkConfiguration['view']['partialRootPath']) && strlen($extbaseFrameworkConfiguration['view']['partialRootPath']) > 0 && method_exists($view, 'setPartialRootPath')) {
389 $view->setPartialRootPath(\TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($extbaseFrameworkConfiguration['view']['partialRootPath']));
390 }
391 }
392
393 /**
394 * Determines the fully qualified view object name.
395 *
396 * @return mixed The fully qualified view object name or FALSE if no matching view could be found.
397 * @api
398 */
399 protected function resolveViewObjectName() {
400 $vendorName = $this->request->getControllerVendorName();
401
402 if ($vendorName !== NULL) {
403 $possibleViewName = str_replace('@vendor', $vendorName, $this->viewObjectNamePattern);
404 } else {
405 $possibleViewName = $this->deprecatedViewObjectNamePattern;
406 }
407
408 $extensionName = $this->request->getControllerExtensionName();
409 $possibleViewName = str_replace('@extension', $extensionName, $possibleViewName);
410 $possibleViewName = str_replace('@controller', $this->request->getControllerName(), $possibleViewName);
411 $possibleViewName = str_replace('@action', ucfirst($this->request->getControllerActionName()), $possibleViewName);
412 $format = $this->request->getFormat();
413 $viewObjectName = str_replace('@format', ucfirst($this->request->getFormat()), $possibleViewName);
414 if (class_exists($viewObjectName) === FALSE) {
415 $viewObjectName = str_replace('@format', '', $possibleViewName);
416 }
417 if (class_exists($viewObjectName) === FALSE && isset($this->viewFormatToObjectNameMap[$format])) {
418 $viewObjectName = $this->viewFormatToObjectNameMap[$format];
419 }
420 return class_exists($viewObjectName) ? $viewObjectName : FALSE;
421 }
422
423 /**
424 * Initializes the view before invoking an action method.
425 *
426 * Override this method to solve assign variables common for all actions
427 * or prepare the view in another way before the action is called.
428 *
429 * @param \TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view The view to be initialized
430 * @return void
431 * @api
432 */
433 protected function initializeView(\TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view) {
434 }
435
436 /**
437 * Initializes the controller before invoking an action method.
438 *
439 * Override this method to solve tasks which all actions have in
440 * common.
441 *
442 * @return void
443 * @api
444 */
445 protected function initializeAction() {
446 }
447
448 /**
449 * A special action which is called if the originally intended action could
450 * not be called, for example if the arguments were not valid.
451 *
452 * The default implementation sets a flash message, request errors and forwards back
453 * to the originating action. This is suitable for most actions dealing with form input.
454 *
455 * We clear the page cache by default on an error as well, as we need to make sure the
456 * data is re-evaluated when the user changes something.
457 *
458 * @return string
459 * @api
460 */
461 protected function errorAction() {
462 $this->clearCacheOnError();
463 if ($this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
464 $errorFlashMessage = $this->getErrorFlashMessage();
465 if ($errorFlashMessage !== FALSE) {
466 $this->controllerContext->getFlashMessageQueue()->addMessage(new \TYPO3\CMS\Core\Messaging\FlashMessage($errorFlashMessage, '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR));
467 }
468 $referringRequest = $this->request->getReferringRequest();
469 if ($referringRequest !== NULL) {
470 $originalRequest = clone $this->request;
471 $this->request->setOriginalRequest($originalRequest);
472 $this->request->setOriginalRequestMappingResults($this->arguments->getValidationResults());
473 $this->forward($referringRequest->getControllerActionName(), $referringRequest->getControllerName(), $referringRequest->getControllerExtensionName(), $referringRequest->getArguments());
474 }
475 $message = 'An error occurred while trying to call ' . get_class($this) . '->' . $this->actionMethodName . '().' . PHP_EOL;
476 foreach ($this->arguments->getValidationResults()->getFlattenedErrors() as $propertyPath => $errors) {
477 foreach ($errors as $error) {
478 $message .= 'Error for ' . $propertyPath . ': ' . $error->render() . PHP_EOL;
479 }
480 }
481 return $message;
482 } else {
483 // @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
484 $this->request->setErrors($this->argumentsMappingResults->getErrors());
485 $errorFlashMessage = $this->getErrorFlashMessage();
486 if ($errorFlashMessage !== FALSE) {
487 $this->controllerContext->getFlashMessageQueue()->addMessage(new \TYPO3\CMS\Core\Messaging\FlashMessage($errorFlashMessage, '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR));
488 }
489 $referrer = $this->request->getInternalArgument('__referrer');
490 if ($referrer !== NULL) {
491 $this->forward($referrer['actionName'], $referrer['controllerName'], $referrer['extensionName'], $this->request->getArguments());
492 }
493 $message = 'An error occurred while trying to call ' . get_class($this) . '->' . $this->actionMethodName . '().' . PHP_EOL;
494 foreach ($this->argumentsMappingResults->getErrors() as $error) {
495 $message .= 'Error: ' . $error->getMessage() . PHP_EOL;
496 }
497 foreach ($this->argumentsMappingResults->getWarnings() as $warning) {
498 $message .= 'Warning: ' . $warning->getMessage() . PHP_EOL;
499 }
500 return $message;
501 }
502 }
503
504 /**
505 * A template method for displaying custom error flash messages, or to
506 * display no flash message at all on errors. Override this to customize
507 * the flash message in your action controller.
508 *
509 * @return string The flash message or FALSE if no flash message should be set
510 * @api
511 */
512 protected function getErrorFlashMessage() {
513 return 'An error occurred while trying to call ' . get_class($this) . '->' . $this->actionMethodName . '()';
514 }
515
516 /**
517 * Checks the request hash (HMAC), if arguments have been touched by the property mapper.
518 *
519 * In case the @dontverifyrequesthash-Annotation has been set, this suppresses the exception.
520 *
521 * @return void
522 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidOrNoRequestHashException In case request hash checking failed
523 * @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
524 */
525 protected function checkRequestHash() {
526 if ($this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
527 // If the new property mapper is enabled, the request hash is not needed anymore.
528 return;
529 }
530 if (!$this->request instanceof \TYPO3\CMS\Extbase\Mvc\Web\Request) {
531 return;
532 }
533 // We only want to check it for now for web requests.
534 if ($this->request->isHmacVerified()) {
535 return;
536 }
537 // all good
538 $verificationNeeded = FALSE;
539 foreach ($this->arguments as $argument) {
540 if ($argument->getOrigin() == \TYPO3\CMS\Extbase\Mvc\Controller\Argument::ORIGIN_NEWLY_CREATED || $argument->getOrigin() == \TYPO3\CMS\Extbase\Mvc\Controller\Argument::ORIGIN_PERSISTENCE_AND_MODIFIED) {
541 $verificationNeeded = TRUE;
542 }
543 }
544 if ($verificationNeeded) {
545 $methodTagsValues = $this->reflectionService->getMethodTagsValues(get_class($this), $this->actionMethodName);
546 if (!isset($methodTagsValues['dontverifyrequesthash'])) {
547 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidOrNoRequestHashException('Request hash (HMAC) checking failed. The parameter __hmac was invalid or not set, and objects were modified.', 1255082824);
548 }
549 }
550 }
551
552 /**
553 * Clear cache of current page on error. Needed because we want a re-evaluation of the data.
554 * Better would be just do delete the cache for the error action, but that is not possible right now.
555 *
556 * @return void
557 */
558 protected function clearCacheOnError() {
559 $extbaseSettings = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
560 if (isset($extbaseSettings['persistence']['enableAutomaticCacheClearing']) && $extbaseSettings['persistence']['enableAutomaticCacheClearing'] === '1') {
561 if (isset($GLOBALS['TSFE'])) {
562 $pageUid = $GLOBALS['TSFE']->id;
563 $this->cacheService->clearPageCache(array($pageUid));
564 }
565 }
566 }
567
568 /**
569 * Returns a map of action method names and their parameters.
570 *
571 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
572 * @return array Array of method parameters by action name
573 */
574 static public function getActionMethodParameters($objectManager) {
575 $reflectionService = $objectManager->get('TYPO3\CMS\Extbase\Reflection\ReflectionService');
576
577 $result = array();
578
579 $className = get_called_class();
580 $methodNames = get_class_methods($className);
581 foreach ($methodNames as $methodName) {
582 if (strlen($methodName) > 6 && strpos($methodName, 'Action', strlen($methodName) - 6) !== FALSE) {
583 $result[$methodName] = $reflectionService->getMethodParameters($className, $methodName);
584 }
585 }
586
587 return $result;
588 }
589 }
590
591 ?>