[FEATURE] Fluid (TemplateView): Made templateRootPath configurable via TypoScript...
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / MVC / Controller / ActionController.php
index 56dd740..2247a64 100644 (file)
  * A multi action controller. This is by far the most common base class for Controllers.
  *
  * @package Extbase
- * @subpackage MVC
+ * @subpackage MVC\Controller
  * @version $ID:$
  */
 class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controller_AbstractController {
 
        /**
         * @var Tx_Extbase_Reflection_Service
-        * @internal
         */
        protected $reflectionService;
 
@@ -46,6 +45,7 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         * If none is available the $defaultViewObjectName will be used and finally
         * an EmptyView will be created.
         * @var Tx_Extbase_MVC_View_ViewInterface
+        * @api
         */
        protected $view = NULL;
 
@@ -53,25 +53,29 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         * Pattern after which the view object name is built if no Fluid template
         * is found.
         * @var string
+        * @api
         */
-       protected $viewObjectNamePattern = 'Tx_@extension_View_@controller_@action';
+       protected $viewObjectNamePattern = 'Tx_@extension_View_@controller_@action@format';
 
        /**
         * The default view object to use if neither a Fluid template nor an action
         * specific view object could be found.
         * @var string
+        * @api
         */
        protected $defaultViewObjectName = NULL;
 
        /**
         * Name of the action method
         * @var string
+        * @api
         */
        protected $actionMethodName = 'indexAction';
 
        /**
         * Name of the special error action method which is called in case of errors
         * @var string
+        * @api
         */
        protected $errorMethodName = 'errorAction';
 
@@ -80,7 +84,6 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         *
         * @param Tx_Extbase_Reflection_Service $reflectionService
         * @return void
-        * @internal
         */
        public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
                $this->reflectionService = $reflectionService;
@@ -144,7 +147,6 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         *
         * @return void
         * @see initializeArguments()
-        * @internal
         */
        protected function initializeActionMethodArguments() {
                $methodParameters = $this->reflectionService->getMethodParameters(get_class($this), $this->actionMethodName);
@@ -166,13 +168,36 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         * specified in the @validate annotations of an action method
         *
         * @return void
-        * @internal
         */
        protected function initializeActionMethodValidators() {
                $validatorConjunctions = $this->validatorResolver->buildMethodArgumentsValidatorConjunctions(get_class($this), $this->actionMethodName);
                foreach ($validatorConjunctions as $argumentName => $validatorConjunction) {
                        if (!isset($this->arguments[$argumentName])) throw new Tx_Extbase_MVC_Exception_NoSuchArgument('Found custom validation rule for non existing argument "' . $argumentName . '" in ' . get_class($this) . '->' . $this->actionMethodName . '().', 1239853108);
-                       $this->arguments[$argumentName]->setValidator($validatorConjunction);
+                       $argument = $this->arguments[$argumentName];
+                       $existingValidator = $argument->getValidator();
+                       if ($existingValidator !== NULL) {
+                               $validatorConjunction->addValidator($existingValidator);
+                       }
+                       $argument->setValidator($validatorConjunction);
+               }
+
+               $this->evaluateDontValidateAnnotations();
+       }
+
+       /**
+        * Parses @dontvalidate annotations of an action method an disables validation for
+        * the specified arguments.
+        *
+        * @return void
+        */
+       protected function evaluateDontValidateAnnotations() {
+               $methodTagsValues = $this->reflectionService->getMethodTagsValues(get_class($this), $this->actionMethodName);
+               if (isset($methodTagsValues['dontvalidate'])) {
+                       foreach ($methodTagsValues['dontvalidate'] as $dontValidateValue) {
+                               $argumentName = substr($dontValidateValue, 1);
+                               if (!isset($this->arguments[$argumentName])) throw new Tx_Extbase_MVC_Exception_NoSuchArgument('Found @dontvalidate annotation for non existing argument "$' . $argumentName . '" in ' . get_class($this) . '->' . $this->actionMethodName . '().', 1249484908);
+                               $this->arguments[$argumentName]->disableValidation();
+                       }
                }
        }
 
@@ -180,12 +205,11 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         * Determines the action method and assures that the method exists.
         *
         * @return string The action method name
-        * @throws Tx_Extbase_Exception_NoSuchAction if the action specified in the request object does not exist (and if there's no default action either).
-        * @internal
+        * @throws Tx_Extbase_MVC_Exception_NoSuchAction if the action specified in the request object does not exist (and if there's no default action either).
         */
        protected function resolveActionMethodName() {
                $actionMethodName = $this->request->getControllerActionName() . 'Action';
-               if (!method_exists($this, $actionMethodName)) throw new Tx_Extbase_Exception_NoSuchAction('An action "' . $actionMethodName . '" does not exist in controller "' . get_class($this) . '".', 1186669086);
+               if (!method_exists($this, $actionMethodName)) throw new Tx_Extbase_MVC_Exception_NoSuchAction('An action "' . $actionMethodName . '" does not exist in controller "' . get_class($this) . '".', 1186669086);
                return $actionMethodName;
        }
 
@@ -198,7 +222,7 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         *
         * @param string $actionMethodName Name of the action method to call
         * @return void
-        * @internal
+        * @api
         */
        protected function callActionMethod() {
                $argumentsAreValid = TRUE;
@@ -225,15 +249,23 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         * the current action.
         *
         * @return void
+        * @api
         */
        protected function resolveView() {
                $view = $this->objectManager->getObject('Tx_Fluid_View_TemplateView');
                $controllerContext = $this->buildControllerContext();
                $view->setControllerContext($controllerContext);
+               
+               // Template Path Override
+               $extbaseFrameworkConfiguration = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
+               if (isset($extbaseFrameworkConfiguration['view']['templateRootPath']) && $extbaseFrameworkConfiguration['view']['templateRootPath']) {
+                       $view->setTemplateRootPath($extbaseFrameworkConfiguration['view']['templateRootPath']);
+               }
+
                if ($view->hasTemplate() === FALSE) {
                        $viewObjectName = $this->resolveViewObjectName();
-                       if ($viewObjectName === FALSE) $viewObjectName = 'Tx_Extbase_MVC_View_EmptyView';
-                       $view = t3lib_div::makeInstance($viewObjectName);
+                       if (class_exists($viewObjectName) === FALSE) $viewObjectName = 'Tx_Extbase_MVC_View_EmptyView';
+                       $view = $this->objectManager->getObject($viewObjectName);
                        $view->setControllerContext($controllerContext);
                }
                if (method_exists($view, 'injectSettings')) {
@@ -248,21 +280,27 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         * Determines the fully qualified view object name.
         *
         * @return mixed The fully qualified view object name or FALSE if no matching view could be found.
+        * @api
         */
        protected function resolveViewObjectName() {
                $possibleViewName = $this->viewObjectNamePattern;
-               $possibleViewName = str_replace('@extension', $this->request->getControllerExtensionName(), $possibleViewName);
+               $extensionName = $this->request->getControllerExtensionName();
+               $subextensionName = $this->request->getControllerSubextensionName();
+               if ($subextensionName !== NULL && $subextensionName !== '') {
+                       $extensionName.= '_' . $subextensionName;
+               }
+               $possibleViewName = str_replace('@extension', $extensionName, $possibleViewName);
                $possibleViewName = str_replace('@controller', $this->request->getControllerName(), $possibleViewName);
                $possibleViewName = str_replace('@action', ucfirst($this->request->getControllerActionName()), $possibleViewName);
 
-               if (class_exists($possibleViewName)) {
-                       return $possibleViewName;
+               $viewObjectName = str_replace('@format', ucfirst($this->request->getFormat()), $possibleViewName);              
+               if (class_exists($viewObjectName) === FALSE) {
+                       $viewObjectName = str_replace('@format', '', $possibleViewName);
                }
-
-               if ($this->defaultViewObjectName !== NULL && class_exists($this->defaultViewObjectName)) {
-                       return $this->defaultViewObjectName;
+               if (class_exists($viewObjectName) === FALSE && $this->defaultViewObjectName !== NULL) {
+                       $viewObjectName = $this->defaultViewObjectName;
                }
-               return FALSE;
+               return $viewObjectName;
        }
 
        /**
@@ -273,6 +311,7 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         *
         * @param Tx_Extbase_View_ViewInterface $view The view to be initialized
         * @return void
+        * @api
         */
        protected function initializeView(Tx_Extbase_MVC_View_ViewInterface $view) {
        }
@@ -284,6 +323,7 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         * common.
         *
         * @return void
+        * @api
         */
        protected function initializeAction() {
        }
@@ -295,11 +335,15 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
         * The default implementation sets a flash message, request errors and forwards back
         * to the originating action. This is suitable for most actions dealing with form input.
         *
+        * We clear the page cache by default on an error as well, as we need to make sure the
+        * data is re-evaluated when the user changes something.
+        *
         * @return string
         * @api
         */
        protected function errorAction() {
                $this->request->setErrors($this->argumentsMappingResults->getErrors());
+               $this->clearCacheOnError();
 
                if ($this->request->hasArgument('__referrer')) {
                        $referrer = $this->request->getArgument('__referrer');
@@ -316,5 +360,21 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
                return $message;
        }
 
+       /**
+        * Clear cache of current page on error. Needed because we want a re-evaluation of the data.
+        * Better would be just do delete the cache for the error action, but that is not possible right now.
+        *
+        * @return void
+        */
+       protected function clearCacheOnError() {
+               $extbaseSettings = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
+               if (isset($extbaseSettings['persistence']['enableAutomaticCacheClearing']) && $extbaseSettings['persistence']['enableAutomaticCacheClearing'] === '1') {
+                       if (isset($GLOBALS['TSFE'])) {
+                               $pageUid = $GLOBALS['TSFE']->id;
+                               Tx_Extbase_Utility_Cache::clearPageCache(array($pageUid));
+                       }
+               }
+       }
+
 }
 ?>
\ No newline at end of file