TYPO3 CMS  TYPO3_6-2
ActionController.php
Go to the documentation of this file.
1 <?php
3 
19 
26 
31  protected $reflectionService;
32 
37  protected $cacheService;
38 
45  protected $view = NULL;
46 
55  protected $viewObjectNamePattern = 'Tx_@extension_View_@controller_@action@format';
56 
61  protected $namespacesViewObjectNamePattern = '@vendor\@extension\View\@controller\@action@format';
62 
72  protected $viewFormatToObjectNameMap = array();
73 
81  protected $defaultViewObjectName = 'TYPO3\\CMS\\Fluid\\View\\TemplateView';
82 
89  protected $actionMethodName = 'indexAction';
90 
97  protected $errorMethodName = 'errorAction';
98 
105 
117  public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request) {
118  return parent::canProcessRequest($request);
119  }
120 
130  public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response) {
131  if (!$this->canProcessRequest($request)) {
132  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);
133  }
134  if ($response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
135  $response->setRequest($request);
136  }
137  $this->request = $request;
138  $this->request->setDispatched(TRUE);
139  $this->response = $response;
140  $this->uriBuilder = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder');
141  $this->uriBuilder->setRequest($request);
142  $this->actionMethodName = $this->resolveActionMethodName();
145  $this->mvcPropertyMappingConfigurationService->initializePropertyMappingConfigurationFromRequest($request, $this->arguments);
146  $this->initializeAction();
147  $actionInitializationMethodName = 'initialize' . ucfirst($this->actionMethodName);
148  if (method_exists($this, $actionInitializationMethodName)) {
149  call_user_func(array($this, $actionInitializationMethodName));
150  }
151  $this->mapRequestArgumentsToControllerArguments();
152  $this->checkRequestHash();
153  $this->controllerContext = $this->buildControllerContext();
154  $this->view = $this->resolveView();
155  if ($this->view !== NULL) {
156  $this->initializeView($this->view);
157  }
158  $this->callActionMethod();
159  }
160 
171  protected function initializeActionMethodArguments() {
172  $methodParameters = $this->reflectionService->getMethodParameters(get_class($this), $this->actionMethodName);
173  foreach ($methodParameters as $parameterName => $parameterInfo) {
174  $dataType = NULL;
175  if (isset($parameterInfo['type'])) {
176  $dataType = $parameterInfo['type'];
177  } elseif ($parameterInfo['array']) {
178  $dataType = 'array';
179  }
180  if ($dataType === NULL) {
181  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);
182  }
183  $defaultValue = isset($parameterInfo['defaultValue']) ? $parameterInfo['defaultValue'] : NULL;
184  $this->arguments->addNewArgument($parameterName, $dataType, $parameterInfo['optional'] === FALSE, $defaultValue);
185  }
186  }
187 
198  protected function initializeActionMethodValidators() {
199 
200  if (!$this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
201  // @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
202 
203  $parameterValidators = $this->validatorResolver->buildMethodArgumentsValidatorConjunctions(get_class($this), $this->actionMethodName);
204  $dontValidateAnnotations = array();
205 
206  $methodTagsValues = $this->reflectionService->getMethodTagsValues(get_class($this), $this->actionMethodName);
207  if (isset($methodTagsValues['dontvalidate'])) {
208  $dontValidateAnnotations = $methodTagsValues['dontvalidate'];
209  }
210 
211  foreach ($this->arguments as $argument) {
212  $validator = $parameterValidators[$argument->getName()];
213  if (array_search('$' . $argument->getName(), $dontValidateAnnotations) === FALSE) {
214  $baseValidatorConjunction = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
215  if ($baseValidatorConjunction !== NULL) {
216  $validator->addValidator($baseValidatorConjunction);
217  }
218  }
219  $argument->setValidator($validator);
220  }
221  } else {
227  $actionMethodParameters = static::getActionMethodParameters($this->objectManager);
228  if (isset($actionMethodParameters[$this->actionMethodName])) {
229  $methodParameters = $actionMethodParameters[$this->actionMethodName];
230  } else {
231  $methodParameters = array();
232  }
233 
239  $parameterValidators = $this->validatorResolver->buildMethodArgumentsValidatorConjunctions(get_class($this), $this->actionMethodName, $methodParameters);
240 
241  foreach ($this->arguments as $argument) {
242  $validator = $parameterValidators[$argument->getName()];
243 
244  $baseValidatorConjunction = $this->validatorResolver->getBaseValidatorConjunction($argument->getDataType());
245  if (count($baseValidatorConjunction) > 0) {
246  $validator->addValidator($baseValidatorConjunction);
247  }
248  $argument->setValidator($validator);
249  }
250  }
251  }
252 
259  protected function resolveActionMethodName() {
260  $actionMethodName = $this->request->getControllerActionName() . 'Action';
261  if (!method_exists($this, $actionMethodName)) {
262  throw new \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchActionException('An action "' . $actionMethodName . '" does not exist in controller "' . get_class($this) . '".', 1186669086);
263  }
264  return $actionMethodName;
265  }
266 
277  protected function callActionMethod() {
278  if ($this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
279  // enabled since Extbase 1.4.0.
280  $preparedArguments = array();
281  foreach ($this->arguments as $argument) {
282  $preparedArguments[] = $argument->getValue();
283  }
284  $validationResult = $this->arguments->getValidationResults();
285  if (!$validationResult->hasErrors()) {
286  $this->emitBeforeCallActionMethodSignal($preparedArguments);
287  $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
288  } else {
289  $methodTagsValues = $this->reflectionService->getMethodTagsValues(get_class($this), $this->actionMethodName);
290  $ignoreValidationAnnotations = array();
291  if (isset($methodTagsValues['ignorevalidation'])) {
292  $ignoreValidationAnnotations = $methodTagsValues['ignorevalidation'];
293  }
294  // if there exist errors which are not ignored with @ignorevalidation => call error method
295  // else => call action method
296  $shouldCallActionMethod = TRUE;
297  foreach ($validationResult->getSubResults() as $argumentName => $subValidationResult) {
298  if (!$subValidationResult->hasErrors()) {
299  continue;
300  }
301  if (array_search('$' . $argumentName, $ignoreValidationAnnotations) !== FALSE) {
302  continue;
303  }
304  $shouldCallActionMethod = FALSE;
305  break;
306  }
307  if ($shouldCallActionMethod) {
308  $this->emitBeforeCallActionMethodSignal($preparedArguments);
309  $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
310  } else {
311  $actionResult = call_user_func(array($this, $this->errorMethodName));
312  }
313  }
314  } else {
315  // @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
316  $preparedArguments = array();
317  foreach ($this->arguments as $argument) {
318  $preparedArguments[] = $argument->getValue();
319  }
320  if ($this->argumentsMappingResults->hasErrors()) {
321  $actionResult = call_user_func(array($this, $this->errorMethodName));
322  } else {
323  $this->emitBeforeCallActionMethodSignal($preparedArguments);
324  $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
325  }
326  }
327  if ($actionResult === NULL && $this->view instanceof ViewInterface) {
328  $this->response->appendContent($this->view->render());
329  } elseif (is_string($actionResult) && strlen($actionResult) > 0) {
330  $this->response->appendContent($actionResult);
331  } elseif (is_object($actionResult) && method_exists($actionResult, '__toString')) {
332  $this->response->appendContent((string)$actionResult);
333  }
334  }
335 
341  protected function emitBeforeCallActionMethodSignal(array $preparedArguments) {
342  $this->signalSlotDispatcher->dispatch(__CLASS__, 'beforeCallActionMethod', array(get_class($this), $this->actionMethodName, $preparedArguments));
343  }
344 
353  protected function resolveView() {
354  $viewObjectName = $this->resolveViewObjectName();
355  if ($viewObjectName !== FALSE) {
357  $view = $this->objectManager->get($viewObjectName);
358  $this->setViewConfiguration($view);
359  if ($view->canRender($this->controllerContext) === FALSE) {
360  unset($view);
361  }
362  }
363  if (!isset($view) && $this->defaultViewObjectName != '') {
365  $view = $this->objectManager->get($this->defaultViewObjectName);
366  $this->setViewConfiguration($view);
367  if ($view->canRender($this->controllerContext) === FALSE) {
368  unset($view);
369  }
370  }
371  if (!isset($view)) {
372  $view = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Mvc\\View\\NotFoundView');
373  $view->assign('errorMessage', 'No template was found. View could not be resolved for action "'
374  . $this->request->getControllerActionName() . '" in class "' . $this->request->getControllerObjectName() . '"');
375  }
376  $view->setControllerContext($this->controllerContext);
377  if (method_exists($view, 'injectSettings')) {
378  $view->injectSettings($this->settings);
379  }
380  $view->initializeView();
381  // In FLOW3, solved through Object Lifecycle methods, we need to call it explicitely
382  $view->assign('settings', $this->settings);
383  // same with settings injection.
384  return $view;
385  }
386 
393  // Template Path Override
394  $extbaseFrameworkConfiguration = $this->configurationManager->getConfiguration(
396  );
397 
398  // set TemplateRootPaths
399  $viewFunctionName = 'setTemplateRootPaths';
400  if (method_exists($view, $viewFunctionName)) {
401  $deprecatedSetting = 'templateRootPath';
402  $setting = 'templateRootPaths';
403  $parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting);
404  // no need to bother if there is nothing to set
405  if ($parameter) {
406  $view->$viewFunctionName($parameter);
407  }
408  }
409 
410  // set LayoutRootPaths
411  $viewFunctionName = 'setLayoutRootPaths';
412  if (method_exists($view, $viewFunctionName)) {
413  $deprecatedSetting = 'layoutRootPath';
414  $setting = 'layoutRootPaths';
415  $parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting);
416  // no need to bother if there is nothing to set
417  if ($parameter) {
418  $view->$viewFunctionName($parameter);
419  }
420  }
421 
422  // set PartialRootPaths
423  $viewFunctionName = 'setPartialRootPaths';
424  if (method_exists($view, $viewFunctionName)) {
425  $deprecatedSetting = 'partialRootPath';
426  $setting = 'partialRootPaths';
427  $parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting);
428  // no need to bother if there is nothing to set
429  if ($parameter) {
430  $view->$viewFunctionName($parameter);
431  }
432  }
433  }
434 
448  protected function getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting = '') {
449 
450  $values = array();
451 
452  if (
453  !empty($extbaseFrameworkConfiguration['view'][$setting])
454  && is_array($extbaseFrameworkConfiguration['view'][$setting])
455  ) {
456  $values = \TYPO3\CMS\Extbase\Utility\ArrayUtility::sortArrayWithIntegerKeys($extbaseFrameworkConfiguration['view'][$setting]);
457  $values = array_reverse($values, TRUE);
458  }
459 
460  // @todo remove handling of deprecatedSetting two versions after 6.2
461  if (
462  isset($extbaseFrameworkConfiguration['view'][$deprecatedSetting])
463  && strlen($extbaseFrameworkConfiguration['view'][$deprecatedSetting]) > 0
464  ) {
465  $values[] = $extbaseFrameworkConfiguration['view'][$deprecatedSetting];
466  }
467 
468  return $values;
469  }
470 
477  protected function resolveViewObjectName() {
478  $vendorName = $this->request->getControllerVendorName();
479 
480  if ($vendorName !== NULL) {
481  $possibleViewName = str_replace('@vendor', $vendorName, $this->namespacesViewObjectNamePattern);
482  } else {
483  $possibleViewName = $this->viewObjectNamePattern;
484  }
485 
486  $possibleViewName = str_replace(
487  array(
488  '@extension',
489  '@controller',
490  '@action'
491  ),
492  array(
493  $this->request->getControllerExtensionName(),
494  $this->request->getControllerName(),
495  ucfirst($this->request->getControllerActionName())
496  ),
497  $possibleViewName
498  );
499  $format = $this->request->getFormat();
500  $viewObjectName = str_replace('@format', ucfirst($format), $possibleViewName);
501  if (class_exists($viewObjectName) === FALSE) {
502  $viewObjectName = str_replace('@format', '', $possibleViewName);
503  }
504  if (isset($this->viewFormatToObjectNameMap[$format]) && class_exists($viewObjectName) === FALSE) {
505  $viewObjectName = $this->viewFormatToObjectNameMap[$format];
506  }
507  return class_exists($viewObjectName) ? $viewObjectName : FALSE;
508  }
509 
521  protected function initializeView(ViewInterface $view) {
522  }
523 
533  protected function initializeAction() {
534  }
535 
549  protected function errorAction() {
550  $this->clearCacheOnError();
551  if ($this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
552  $errorFlashMessage = $this->getErrorFlashMessage();
553  if ($errorFlashMessage !== FALSE) {
554  $errorFlashMessageObject = new \TYPO3\CMS\Core\Messaging\FlashMessage(
555  $errorFlashMessage,
556  '',
557  \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR
558  );
559  $this->controllerContext->getFlashMessageQueue()->enqueue($errorFlashMessageObject);
560  }
561  $referringRequest = $this->request->getReferringRequest();
562  if ($referringRequest !== NULL) {
563  $originalRequest = clone $this->request;
564  $this->request->setOriginalRequest($originalRequest);
565  $this->request->setOriginalRequestMappingResults($this->arguments->getValidationResults());
566  $this->forward($referringRequest->getControllerActionName(), $referringRequest->getControllerName(), $referringRequest->getControllerExtensionName(), $referringRequest->getArguments());
567  }
568  $message = 'An error occurred while trying to call ' . get_class($this) . '->' . $this->actionMethodName . '().' . PHP_EOL;
569  return $message;
570  } else {
571  // @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
572  $this->request->setErrors($this->argumentsMappingResults->getErrors());
573  $errorFlashMessage = $this->getErrorFlashMessage();
574  if ($errorFlashMessage !== FALSE) {
575  $errorFlashMessageObject = new \TYPO3\CMS\Core\Messaging\FlashMessage(
576  $errorFlashMessage,
577  '',
578  \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR
579  );
580  $this->controllerContext->getFlashMessageQueue()->enqueue($errorFlashMessageObject);
581  }
582  $referrer = NULL;
583  if ($this->request instanceof Request) {
584  $referrer = $this->request->getValidatedReferrerArguments();
585  }
586  if ($referrer !== NULL) {
587  $this->forward($referrer['actionName'], $referrer['controllerName'], $referrer['extensionName'], $this->request->getArguments());
588  }
589  $message = 'An error occurred while trying to call ' . get_class($this) . '->' . $this->actionMethodName . '().' . PHP_EOL;
590  return $message;
591  }
592  }
593 
602  protected function getErrorFlashMessage() {
603  return 'An error occurred while trying to call ' . get_class($this) . '->' . $this->actionMethodName . '()';
604  }
605 
615  protected function checkRequestHash() {
616  if ($this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
617  // If the new property mapper is enabled, the request hash is not needed anymore.
618  return;
619  }
620  if (!$this->request instanceof \TYPO3\CMS\Extbase\Mvc\Web\Request) {
621  return;
622  }
623  // We only want to check it for now for web requests.
624  if ($this->request->isHmacVerified()) {
625  return;
626  }
627  // all good
628  $verificationNeeded = FALSE;
629  foreach ($this->arguments as $argument) {
631  $verificationNeeded = TRUE;
632  }
633  }
634  if ($verificationNeeded) {
635  $methodTagsValues = $this->reflectionService->getMethodTagsValues(get_class($this), $this->actionMethodName);
636  if (!isset($methodTagsValues['dontverifyrequesthash'])) {
637  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);
638  }
639  }
640  }
641 
648  protected function clearCacheOnError() {
649  $extbaseSettings = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
650  if (isset($extbaseSettings['persistence']['enableAutomaticCacheClearing']) && $extbaseSettings['persistence']['enableAutomaticCacheClearing'] === '1') {
651  if (isset($GLOBALS['TSFE'])) {
652  $pageUid = $GLOBALS['TSFE']->id;
653  $this->cacheService->clearPageCache(array($pageUid));
654  }
655  }
656  }
657 
665  static public function getActionMethodParameters($objectManager) {
666  $reflectionService = $objectManager->get('TYPO3\CMS\Extbase\Reflection\ReflectionService');
667 
668  $result = array();
669 
670  $className = get_called_class();
671  $methodNames = get_class_methods($className);
672  foreach ($methodNames as $methodName) {
673  if (strlen($methodName) > 6 && strpos($methodName, 'Action', strlen($methodName) - 6) !== FALSE) {
674  $result[$methodName] = $reflectionService->getMethodParameters($className, $methodName);
675  }
676  }
677 
678  return $result;
679  }
680 }
canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request)
forward($actionName, $controllerName=NULL, $extensionName=NULL, array $arguments=NULL)
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting='')
processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]