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