[FEATURE] Descriptive error on invalid action name
authorClaus Due <claus@wildside.dk>
Sat, 20 Aug 2011 14:57:08 +0000 (16:57 +0200)
committerBastian Waidelich <bastian@typo3.org>
Thu, 15 Sep 2011 15:48:24 +0000 (17:48 +0200)
This adds an additional check to determine if an action was specified
but does not exist in allowed actions for the current plugin.

By default, if an invalid action is specified, an InvalidActionName
Exception is thrown with the message
"There is no action <actionName> for controller <controllerName>"

If the option mvc.throwPageNotFoundExceptionIfActionCantBeResolved is
enabled (globally or just for the extension/plugin) a
t3lib_error_http_PageNotFoundException is thrown instead resulting
in a 404 error page. This is disabled by default.

The previous implementation silently used the default action if an
invalid action was specified. We consider this as a non-breaking
change nevertheless because it is very unlikely that someone was
relying on that behavior.

Thanks to Nathan L., Martin K. & Claus D. for reporting and patches!

Fixes: #5961
Change-Id: I25953da471968d7d2f34fe28d676e9de22abefc9

typo3/sysext/extbase/Classes/MVC/Web/RequestBuilder.php
typo3/sysext/extbase/Tests/Unit/MVC/Web/RequestBuilderTest.php
typo3/sysext/extbase/ext_typoscript_setup.txt

index afd1893..2af2650 100644 (file)
@@ -154,30 +154,8 @@ class Tx_Extbase_MVC_Web_RequestBuilder implements t3lib_Singleton {
                $pluginNamespace = $this->extensionService->getPluginNamespace($this->extensionName, $this->pluginName);
                $parameters = t3lib_div::_GPmerged($pluginNamespace);
 
-               if (is_string($parameters['controller']) && array_key_exists($parameters['controller'], $this->allowedControllerActions)) {
-                       $controllerName = filter_var($parameters['controller'], FILTER_SANITIZE_STRING);
-               } elseif (!empty($this->defaultControllerName)) {
-                       $controllerName = $this->defaultControllerName;
-               } else {
-                       throw new Tx_Extbase_MVC_Exception(
-                               'The default controller can not be determined.<br />'
-                               . 'Please check for Tx_Extbase_Utility_Extension::configurePlugin() in your ext_localconf.php.',
-                               1295479650
-                       );
-               }
-
-               $allowedActions = $this->allowedControllerActions[$controllerName];
-               if (is_string($parameters['action']) && is_array($allowedActions) && in_array($parameters['action'], $allowedActions)) {
-                       $actionName = filter_var($parameters['action'], FILTER_SANITIZE_STRING);
-               } elseif (!empty($this->defaultActionName)) {
-                       $actionName = $this->defaultActionName;
-               } else {
-                       throw new Tx_Extbase_MVC_Exception(
-                               'The default action can not be determined for controller "' . $controllerName . '".<br />'
-                               . 'Please check Tx_Extbase_Utility_Extension::configurePlugin() in your ext_localconf.php.',
-                               1295479651
-                       );
-               }
+               $controllerName = $this->resolveControllerName($parameters);
+               $actionName = $this->resolveActionName($controllerName, $parameters);
 
                $request = $this->objectManager->create('Tx_Extbase_MVC_Web_Request');
                $request->setPluginName($this->pluginName);
@@ -201,6 +179,66 @@ class Tx_Extbase_MVC_Web_RequestBuilder implements t3lib_Singleton {
                return $request;
        }
 
+       /**
+        * Returns the current ControllerName extracted from given $parameters.
+        * If no controller is specified, the defaultControllerName will be returned.
+        * If that's not available, an exception is thrown.
+        *
+        * @param array $parameters
+        * @return string
+        * @throws Tx_Extbase_MVC_Exception if the controller could not be resolved
+        */
+       protected function resolveControllerName(array $parameters) {
+               if (isset($parameters['controller']) && in_array($parameters['controller'], $this->allowedControllerActions)) {
+                       return filter_var($parameters['controller'], FILTER_SANITIZE_STRING);
+               } elseif (!empty($this->defaultControllerName)) {
+                       return $this->defaultControllerName;
+               } else {
+                       throw new Tx_Extbase_MVC_Exception(
+                               'The default controller can not be determined. Please check for Tx_Extbase_Utility_Extension::configurePlugin() in your ext_localconf.php.',
+                               1295479650
+                       );
+               }
+       }
+
+       /**
+        * Returns the current actionName extracted from given $parameters.
+        * If no action is specified, the defaultActionName will be returned.
+        * If that's not available or the specified action is not defined in the current plugin, an exception is thrown.
+        *
+        * @param $controllerName
+        * @param array $parameters
+        * @return string
+        * @throws t3lib_error_http_PageNotFoundException|Tx_Extbase_MVC_Exception|Tx_Extbase_MVC_Exception_InvalidActionName if the action could not be resolved
+        */
+       protected function resolveActionName($controllerName, array $parameters) {
+               if (!isset($parameters['action']) || strlen($parameters['action']) === 0) {
+                       if (!empty($this->defaultActionName)) {
+                               return $this->defaultActionName;
+                       }
+                       throw new Tx_Extbase_MVC_Exception(
+                               'The default action can not be determined for controller "' . $controllerName . '". Please check Tx_Extbase_Utility_Extension::configurePlugin() in your ext_localconf.php.',
+                               1295479651
+                       );
+               }
+               $actionName = $parameters['action'];
+               $allowedActions = $this->allowedControllerActions[$controllerName];
+               if (!in_array($actionName, $allowedActions)) {
+                       $configuration = $this->configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
+                       if (isset($configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) && (boolean)$configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) {
+                               throw new t3lib_error_http_PageNotFoundException(
+                                       'The requested resource was not found',
+                                       1313857897
+                               );
+                       }
+                       throw new Tx_Extbase_MVC_Exception_InvalidActionName(
+                               'There is no action "' . $actionName . '" for controller "' . $controllerName . '".',
+                               1313855173
+                       );
+               }
+               return filter_var($actionName, FILTER_SANITIZE_STRING);
+       }
+
 
 }
 ?>
\ No newline at end of file
index de09a75..332b5e0 100644 (file)
@@ -251,6 +251,46 @@ class Tx_Extbase_Tests_Unit_MVC_Web_RequestBuilderTest extends Tx_Extbase_Tests_
 
        /**
         * @test
+        * @expectedException Tx_Extbase_MVC_Exception_InvalidActionName
+        */
+       public function resolveActionNameThrowsInvalidActionExceptionIfSpecifiedActionIsNotAllowed() {
+               $this->requestBuilder->injectConfigurationManager($this->mockConfigurationManager);
+               $this->requestBuilder->injectExtensionService($this->mockExtensionService);
+               $parameters = array('action' => 'new');
+               $this->requestBuilder->_call('resolveActionName', 'TheSecondController', $parameters);
+       }
+
+       /**
+        * @test
+        * @expectedException t3lib_error_http_PageNotFoundException
+        */
+       public function resolveActionNameThrowsPageNotFoundExceptionIfSpecifiedActionIsNotAllowedAndPageNotFoundExceptionIsConfigured() {
+               $this->configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved'] = 1;
+               $this->mockConfigurationManager->expects($this->any())->method('getConfiguration')->will($this->returnValue($this->configuration));
+               $this->requestBuilder->injectConfigurationManager($this->mockConfigurationManager);
+               $this->requestBuilder->injectExtensionService($this->mockExtensionService);
+               $parameters = array('action' => 'new');
+               $this->requestBuilder->_call('resolveActionName', 'TheSecondController', $parameters);
+       }
+
+       /**
+        * @test
+        * @expectedException Tx_Extbase_MVC_Exception
+        */
+       public function buildThrowsExceptionIfNoDefaultControllerCanBeResolved() {
+               $this->configuration['controllerConfiguration'] = array(
+                       '' => array(
+                               'actions' => array('foo')
+                       )
+               );
+               $this->mockConfigurationManager->expects($this->any())->method('getConfiguration')->will($this->returnValue($this->configuration));
+               $this->requestBuilder->injectConfigurationManager($this->mockConfigurationManager);
+               $this->requestBuilder->injectExtensionService($this->mockExtensionService);
+               $this->requestBuilder->build();
+       }
+
+       /**
+        * @test
         */
        public function buildSetsParametersFromGetAndPostVariables() {
                $this->configuration['extensionName'] = 'SomeExtensionName';
@@ -328,5 +368,6 @@ class Tx_Extbase_Tests_Unit_MVC_Web_RequestBuilderTest extends Tx_Extbase_Tests_
                $actualResult = $this->requestBuilder->_get('allowedControllerActions');
                $this->assertEquals($expectedResult, $actualResult);
        }
+
 }
 ?>
\ No newline at end of file
index 24e583d..5454a06 100644 (file)
@@ -12,6 +12,7 @@ config.tx_extbase {
                        Tx_Extbase_MVC_Web_FrontendRequestHandler = Tx_Extbase_MVC_Web_FrontendRequestHandler
                        Tx_Extbase_MVC_Web_BackendRequestHandler = Tx_Extbase_MVC_Web_BackendRequestHandler
                }
+               throwPageNotFoundExceptionIfActionCantBeResolved = 0
        }
        persistence{
                enableAutomaticCacheClearing = 1