EXTMVC:
authorJochen Rau <j.rau@web.de>
Tue, 24 Mar 2009 07:45:10 +0000 (07:45 +0000)
committerJochen Rau <j.rau@web.de>
Tue, 24 Mar 2009 07:45:10 +0000 (07:45 +0000)
* Refactored dispatcher
* Moved isCachableAction() to the ActionController
* Fixed invokation of EmptyView if no view was specified
* Fixed type of cruser_id (now Integer)
* Revised and refactored ORM
* removed $aggregateRootClassName from Persistence Repository

typo3/sysext/extbase/Classes/Controller/TX_EXTMVC_Controller_AbstractController.php
typo3/sysext/extbase/Classes/Controller/TX_EXTMVC_Controller_ActionController.php
typo3/sysext/extbase/Classes/Persistence/Mapper/TX_EXTMVC_Persistence_Mapper_DataMap.php
typo3/sysext/extbase/Classes/Persistence/Mapper/TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper.php
typo3/sysext/extbase/Classes/Persistence/TX_EXTMVC_Persistence_Repository.php
typo3/sysext/extbase/Classes/Persistence/TX_EXTMVC_Persistence_RepositoryInterface.php
typo3/sysext/extbase/Classes/Persistence/TX_EXTMVC_Persistence_Session.php
typo3/sysext/extbase/class.tx_extmvc_dispatcher.php

index 63629a1..fb0a2a7 100755 (executable)
@@ -102,19 +102,6 @@ abstract class TX_EXTMVC_Controller_AbstractController implements TX_EXTMVC_Cont
                $this->mapRequestArgumentsToLocalArguments();
        }
 
-       /**
-        * Returns TRUE if the given action (a name of an action like 'show'; without 
-        * trailing 'Action') should be cached, otherwise it returns FALSE.
-        *
-        * @param string $actionName 
-        * @return void
-        * @author Jochen Rau <jochen.rau@typoplanet.de>
-        */
-       public function isCachableAction($actionName) {
-               if (in_array($actionName, $this->nonCachableActions)) return FALSE;
-               return TRUE;
-       }
-
        /**
         * Initializes (registers / defines) arguments of this controller.
         *
index a6d8f1c..1a1cf73 100644 (file)
@@ -97,6 +97,18 @@ class TX_EXTMVC_Controller_ActionController extends TX_EXTMVC_Controller_Abstrac
                if (!method_exists($this, $actionMethodName)) throw new TX_EXTMVC_Exception_NoSuchAction('An action "' . $actionMethodName . '" does not exist in controller "' . get_class($this) . '".', 1186669086);
                return $actionMethodName;
        }
+       
+       /**
+        * Returns TRUE if the given action (a name of an action like 'show'; without 
+        * trailing 'Action') should be cached, otherwise it returns FALSE.
+        *
+        * @param string $actionName 
+        * @return void
+        * @author Jochen Rau <jochen.rau@typoplanet.de>
+        */
+       public function isCachableAction($actionName) {
+                return !in_array($actionName, $this->nonCachableActions);
+       }
 
        /**
         * Calls the specified action method and passes the arguments.
@@ -124,7 +136,7 @@ class TX_EXTMVC_Controller_ActionController extends TX_EXTMVC_Controller_Abstrac
         */
        protected function initializeView() {
                $viewObjectName = ($this->viewObjectName === NULL) ? $this->resolveViewObjectName() : $this->viewObjectName;
-               if ($viewObjectName === FALSE) $viewObjectName = 'TX_EXTMVC_View_EmptyView';
+               if (!class_exists($viewObjectName)) $viewObjectName = 'TX_EXTMVC_View_EmptyView';
 
                $this->view = t3lib_div::makeInstance($viewObjectName);
                $this->view->setRequest($this->request);
index aede485..1818a45 100644 (file)
@@ -53,6 +53,11 @@ class TX_EXTMVC_Persistence_Mapper_DataMap {
         **/
        protected $columnMaps;
 
+       /**
+        * Constructs this DataMap
+        *
+        * @param string $className The class name. This determines the table to fetch the configuration for
+        */
        public function __construct($className) {
                $this->setClassName($className);
                // SK: strtolower(..) is the wrong conversion for the class name. See the notice in the dispatcher (tt_news ->tx_ttnews)
@@ -100,7 +105,7 @@ class TX_EXTMVC_Persistence_Mapper_DataMap {
                $this->addColumn('pid', TX_EXTMVC_Persistence_Mapper_ColumnMap::TYPE_INTEGER);
                $this->addColumn('tstamp', TX_EXTMVC_Persistence_Mapper_ColumnMap::TYPE_DATE);
                $this->addColumn('crdate', TX_EXTMVC_Persistence_Mapper_ColumnMap::TYPE_DATE);
-               $this->addColumn('cruser_id', TX_EXTMVC_Persistence_Mapper_ColumnMap::TYPE_DATE);
+               $this->addColumn('cruser_id', TX_EXTMVC_Persistence_Mapper_ColumnMap::TYPE_INTEGER);
                if ($this->getDeletedColumnName() !== NULL) {
                        $this->addColumn($this->getDeletedColumnName(), TX_EXTMVC_Persistence_Mapper_ColumnMap::TYPE_BOOLEAN);
                }
@@ -185,8 +190,7 @@ class TX_EXTMVC_Persistence_Mapper_DataMap {
         * @return boolean TRUE if the property is persistable (configured in $TCA)
         */
        public function isPersistableProperty($propertyName) {
-               if (array_key_exists($propertyName, $this->columnMaps)) return TRUE;
-               return FALSE;
+               return isset($this->columnMaps[$propertyName]);
        }
 
        /**
@@ -214,6 +218,7 @@ class TX_EXTMVC_Persistence_Mapper_DataMap {
         * @param mixed $fieldValue The field value
         * @return mixed The converted value
         */
+       // TODO convertion has to be revised
        public function convertFieldValueToPropertyValue($propertyName, $fieldValue) {
                $columnMap = $this->getColumnMap($propertyName);
                if ($columnMap->getTypeOfValue() === TX_EXTMVC_Persistence_Mapper_ColumnMap::TYPE_DATE) {
index f2badea..ef819a6 100644 (file)
@@ -68,15 +68,16 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
        /**
         * Finds objects matching a given WHERE Clause
         *
-        * @param string $className The class name
-        * @param string $arguments The WHERE statement
-        * @return void
+        * @param string $where WHERE statement
+        * @param string $groupBy GROUP BY statement
+        * @param string $orderBy ORDER BY statement
+        * @param string $limit LIMIT statement
+        * @return array An array of reconstituted domain objects
         */
-       public function findWhere($className, $where = '1=1') {
+       public function findWhere($className, $where = '1=1', $groupBy = '', $orderBy = '', $limit = '') {
                // TODO check PID for records
                $dataMap = $this->getDataMap($className);
-               // SK: Support for GroupBy, OrderBy, Limit!
-               $rows = $this->fetch($dataMap, $where);
+               $rows = $this->fetch($dataMap, $where, $groupBy, $orderBy, $limit);
                $objects = $this->reconstituteObjects($dataMap, $rows);
                return $objects;
        }
@@ -84,18 +85,18 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
        /**
         * Fetches rows from the database by given SQL statement snippets
         *
-        * @param string $from FROM statement
+        * @param TX_EXTMVC_Persistence_Mapper_DataMap $dataMap The Data Map holding the configuration of the table and the Column Maps
         * @param string $where WHERE statement
         * @param string $groupBy GROUP BY statement
         * @param string $orderBy ORDER BY statement
         * @param string $limit LIMIT statement
-        * @return void
+        * @return array The matched rows
         */
        public function fetch($dataMap, $where = '1=1', $groupBy = '', $orderBy = '', $limit = '') {
                $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
                        '*', // TODO limit fetched fields
                        $dataMap->getTableName(),
-                       $where . $this->cObj->enableFields($dataMap->getTableName()) . $this->cObj->enableFields($dataMap->getTableName()),
+                       $where . $this->cObj->enableFields($dataMap->getTableName()),
                        $groupBy,
                        $orderBy,
                        $limit
@@ -108,17 +109,17 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
        /**
         * Fetches a rows from the database by given SQL statement snippets taking a relation table into account
         *
-        * @param string Optional additional WHERE clauses put in the end of the query. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself! DO NOT PUT IN GROUP BY, ORDER BY or LIMIT! You have to prepend 'AND ' to this parameter yourself!
-        * @param string Optional GROUP BY field(s), if none, supply blank string.
-        * @param string Optional ORDER BY field(s), if none, supply blank string.
-        * @param string Optional LIMIT value ([begin,]max), if none, supply blank string.
+        * @param string Optional WHERE clauses put in the end of the query, defaults to '1=1. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
+        * @param string Optional GROUP BY field(s), defaults to blank string.
+        * @param string Optional ORDER BY field(s), defaults to blank string.
+        * @param string Optional LIMIT value ([begin,]max), defaults to blank string.
         */
        // SK: Are SQL injections possible here? Can we somehow prevent them? I did not check it thoroughly yet, but I think they are possible
        public function fetchWithRelationTable($parentObject, $columnMap, $where = '1=1', $groupBy = '', $orderBy = '', $limit = '') {
                $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
                        $columnMap->getChildTableName() . '.*, ' . $columnMap->getRelationTableName() . '.*',
                        $columnMap->getChildTableName() . ' LEFT JOIN ' . $columnMap->getRelationTableName() . ' ON (' . $columnMap->getChildTableName() . '.uid=' . $columnMap->getRelationTableName() . '.uid_foreign)',
-                       $where . ' AND ' . $columnMap->getRelationTableName() . '.uid_local=' . t3lib_div::intval_positive($parentObject->getUid()) . $this->cObj->enableFields($columnMap->getChildTableName()) . $this->cObj->enableFields($columnMap->getChildTableName()),
+                       $where . ' AND ' . $columnMap->getRelationTableName() . '.uid_local=' . t3lib_div::intval_positive($parentObject->getUid()) . $this->cObj->enableFields($columnMap->getChildTableName()),
                        $groupBy,
                        $orderBy,
                        $limit
@@ -254,9 +255,9 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
                        );
                $object->_reconstituteProperty('uid', $GLOBALS['TYPO3_DB']->sql_insert_id());
 
-               $recursionMode = TRUE; // TODO make parametric
+               $recursionMode = TRUE; // TODO Make this configurable
                if ($recursionMode === TRUE) {
-                       $this->processRelations($object, $propertyName, 'persist', $relations);
+                       $this->persistRelations($object, $propertyName, $relations);
                }
        }
 
@@ -271,7 +272,6 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
                $dataMap = $this->getDataMap(get_class($object));
                $relations = $this->getRelations($dataMap, $properties);
                $row = $this->getRow($dataMap, $properties);
-
                unset($row['uid']);
                $row['crdate'] = time();
                if (!empty($GLOBALS['TSFE']->fe_user->user['uid'])) {
@@ -299,7 +299,7 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
 
                $recursionMode = TRUE; // TODO make parametric
                if ($recursionMode === TRUE) {
-                       $this->processRelations($object, $propertyName, 'persist', $relations);
+                       $this->persistRelations($object, $propertyName, $relations);
                }
        }
 
@@ -331,7 +331,7 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
                }
 
                if ($recursionMode === TRUE) {
-                       $this->processRelations($object, $propertyName, 'delete', $relations);
+                       $this->processRelations($object, $propertyName, $relations);
                }
        }
 
@@ -381,37 +381,47 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
        }
 
        /**
-        * Processes all relations of an object. It also updates relation tables.
+        * Inserts and updates all relations of an object. It also updates relation tables.
         *
         * @param TX_EXTMVC_DomainObject_AbstractDomainObject $object The object for which the relations should be updated
         * @param string $propertyName The name of the property holding the related child objects
-        * @param string $command The command (one of "persist", "delete"). Persist updates and inserts records as needed
         * @param array $relations The queued relations
         * @return void
         */
-       protected function processRelations(TX_EXTMVC_DomainObject_AbstractDomainObject $object, $propertyName, $command, array $relations) {
+       protected function persistRelations(TX_EXTMVC_DomainObject_AbstractDomainObject $object, $propertyName, array $relations) {
                $dataMap = $this->getDataMap(get_class($object));
-               if ($command === 'persist') {
-                       foreach ($relations as $propertyName => $relatedObjects) {
-                               if (!empty($relatedObjects)) {
-                                       $typeOfRelation = $dataMap->getColumnMap($propertyName)->getTypeOfRelation();
-                                       foreach ($relatedObjects as $relatedObject) {
-                                               if (!$this->session->isReconstitutedObject($relatedObject)) {
-                                                       $this->insertObject($relatedObject, $object, $propertyName);
-                                                       if ($typeOfRelation === TX_EXTMVC_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
-                                                               $this->insertRelationInRelationTable($relatedObject, $object, $propertyName);
-                                                       }
-                                               } elseif ($this->session->isReconstitutedObject($relatedObject) && $relatedObject->_isDirty()) {
-                                                       $this->updateObject($relatedObject, $object, $propertyName);
+               foreach ($relations as $propertyName => $relatedObjects) {
+                       if (!empty($relatedObjects)) {
+                               $typeOfRelation = $dataMap->getColumnMap($propertyName)->getTypeOfRelation();
+                               foreach ($relatedObjects as $relatedObject) {
+                                       if (!$this->session->isReconstitutedObject($relatedObject)) {
+                                               $this->insertObject($relatedObject, $object, $propertyName);
+                                               if ($typeOfRelation === TX_EXTMVC_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
+                                                       $this->insertRelationInRelationTable($relatedObject, $object, $propertyName);
                                                }
+                                       } elseif ($this->session->isReconstitutedObject($relatedObject) && $relatedObject->_isDirty()) {
+                                               $this->updateObject($relatedObject, $object, $propertyName);
                                        }
                                }
-                               if ($typeOfRelation === TX_EXTMVC_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
-                                       $this->updateRelationsInRelationTable($relatedObjects, $object, $propertyName);
-                               }
                        }
-               } elseif ($command === 'delete') {
-                       foreach ($relations as $propertyName => $relatedObjects) {
+                       if ($typeOfRelation === TX_EXTMVC_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
+                               $this->updateRelationsInRelationTable($relatedObjects, $object, $propertyName);
+                       }
+               }
+       }
+
+       /**
+        * Deletes all relations of an object. It also updates relation tables.
+        *
+        * @param TX_EXTMVC_DomainObject_AbstractDomainObject $object The object for which the relations should be updated
+        * @param string $propertyName The name of the property holding the related child objects
+        * @param array $relations The queued relations
+        * @return void
+        */
+       protected function deleteRelations(TX_EXTMVC_DomainObject_AbstractDomainObject $object, $propertyName, array $relations) {
+               $dataMap = $this->getDataMap(get_class($object));
+               foreach ($relations as $propertyName => $relatedObjects) {
+                       if (is_array($relatedObjects)) {
                                foreach ($relatedObjects as $relatedObject) {
                                        $this->deleteObject($relatedObject, $object, $propertyName);
                                        if ($dataMap->getColumnMap($propertyName)->getTypeOfRelation() === TX_EXTMVC_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
@@ -439,10 +449,13 @@ class TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Singl
                        'sorting' => 9999 // TODO sorting of mm table items
                        );
                $tableName = $dataMap->getColumnMap($parentPropertyName)->getRelationTableName();
+               // debug($rowToInsert, $tableName);
                $res = $GLOBALS['TYPO3_DB']->exec_INSERTquery(
                        $tableName,
                        $rowToInsert
                        );
+               // var_dump($res);
+               // debug(mysql_error());
        }
 
        /**
index cb906f8..47e8eea 100644 (file)
@@ -80,33 +80,10 @@ abstract class TX_EXTMVC_Persistence_Repository implements TX_EXTMVC_Persistence
                if (substr($repositoryClassName, -10) == 'Repository' && substr($repositoryClassName, -11, 1) != '_') {
                        $this->aggregateRootClassName = substr($repositoryClassName, 0, -10);
                }
+               // TODO not entity or empty aggregateRootClassName -> exception
                $this->dataMapper = t3lib_div::makeInstance('TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper'); // singleton
                $this->session = t3lib_div::makeInstance('TX_EXTMVC_Persistence_Session'); // singleton
                $this->session->registerAggregateRootClassName($this->aggregateRootClassName);
-               // FIXIT auto resolve findBy properties; black list
-               // SK: see above comment
-               $this->allowedFindByProperties = array('name', 'blog');
-       }
-
-       /**
-        * Sets the class name of the aggregate root
-        *
-        * @param string $aggregateRootClassName
-        * @return void
-        */
-       public function setAggregateRootClassName($aggregateRootClassName) {
-               $this->aggregateRootClassName = $aggregateRootClassName;
-               $this->session->registerAggregateRootClassName($this->aggregateRootClassName);
-       }
-
-       /**
-        * Returns the class name of the aggregate root
-        *
-        * @return string The class name of the aggregate root
-        */
-       public function getAggregateRootClassName() {
-               // TODO throw exception if not set
-               return $this->aggregateRootClassName;
        }
 
        /**
@@ -134,7 +111,7 @@ abstract class TX_EXTMVC_Persistence_Repository implements TX_EXTMVC_Persistence
        }
 
        /**
-        * Dispatches magic methods (findByProperty())
+        * Dispatches magic methods (findBy[Property]())
         *
         * @param string $methodName The name of the magic method
         * @param string $arguments The arguments of the magic method
@@ -142,20 +119,19 @@ abstract class TX_EXTMVC_Persistence_Repository implements TX_EXTMVC_Persistence
         * @return void
         */
        public function __call($methodName, $arguments) {
-               if (substr($methodName, 0, 6) === 'findBy') {
+               if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
                        $propertyName = TX_EXTMVC_Utility_Strings::lowercaseFirst(substr($methodName,6));
                        if (!in_array($propertyName, $this->blacklistedFindByProperties)) {
                                return $this->findByProperty($propertyName, $arguments[0]);
                        }
-               } elseif (substr($methodName, 0, 9) === 'findOneBy') {
+               } elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
                        $propertyName = TX_EXTMVC_Utility_Strings::lowercaseFirst(substr($methodName,9));
                        if (!in_array($propertyName, $this->blacklistedFindByProperties)) {
                                $result = $this->findByProperty($propertyName, $arguments[0]);
                                if (empty($result)) {
                                        return FALSE;
                                } else {
-                                       return $result[0]; // TODO LIMIT
-                                       // SK: Implement LIMIT!
+                                       return $result[0]; // TODO Implement LIMIT
                                }
                        }
                }
@@ -168,7 +144,6 @@ abstract class TX_EXTMVC_Persistence_Repository implements TX_EXTMVC_Persistence
         * @return array An array of objects, empty if no objects found
         */
        public function findAll() {
-               // TODO implement support for SQL LIMIT
                return $this->dataMapper->findWhere($this->aggregateRootClassName);
        }
 
@@ -190,15 +165,31 @@ abstract class TX_EXTMVC_Persistence_Repository implements TX_EXTMVC_Persistence
         * @param string $arguments The arguments of the magic findBy method
         * @return array The result
         */
-       private function findByProperty($propertyName, $value) {
+       protected function findByProperty($propertyName, $value) {
                // TODO implement support for SQL LIMIT
                if ($value instanceof TX_EXTMVC_DomainObject_AbstractDomainObject) {
-                       $where = $propertyName . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value->getUid(), 'foo');
+                       $where = $propertyName . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value->getUid(), '');
                } else {
-                       $where = $propertyName . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value, 'foo');
+                       $where = $propertyName . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value, '');
                }
                return $this->dataMapper->findWhere($this->aggregateRootClassName, $where);
        }
 
+       /**
+        * Delegates findWhere() to the ObjectRelationalMapper
+        *
+        * @param string $className The class name
+        * @param string $arguments The WHERE statement
+        * @return void
+        */
+       public function findWhere($className, $where = '1=1', $groupBy = '', $orderBy = '', $limit = '') {
+               // TODO check PID for records? - no
+               // TODO Switch for enableFields; TRUE by default
+               $dataMap = $this->getDataMap($className);
+               $rows = $this->fetch($dataMap, $where, $groupBy, $orderBy, $limit);
+               $objects = $this->reconstituteObjects($dataMap, $rows);
+               return $objects;
+       }
+
 }
 ?>
\ No newline at end of file
index 738189e..75ef7fe 100644 (file)
  */
 interface TX_EXTMVC_Persistence_RepositoryInterface {
 
-       /**
-        * Sets the class name of the aggregare root
-        *
-        * @param string $aggregateRootClassName 
-        * @return void
-        */
-       public function setAggregateRootClassName($aggregateRootClassName);
-
-       /**
-        * Returns the class name of the aggregare root
-        *
-        * @return string The class name of the aggregate root
-        */
-       public function getAggregateRootClassName();
-
        /**
         * Adds an object to this repository.
         *
@@ -61,6 +46,13 @@ interface TX_EXTMVC_Persistence_RepositoryInterface {
         * @return void
         */
        public function remove($object);
+       
+       /**
+        * Returns all objects of this repository.
+        *
+        * @return array An array of objects, empty if no objects found
+        */
+       public function findAll();
 
 }
 ?>
\ No newline at end of file
index 913e557..8721f89 100644 (file)
@@ -296,7 +296,7 @@ class TX_EXTMVC_Persistence_Session implements t3lib_singleton {
         * @return void
         */
        public function commit() {
-               $dataMapper = t3lib_div::makeInstance('TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper'); // singleton;
+               $dataMapper = t3lib_div::makeInstance('TX_EXTMVC_Persistence_Mapper_ObjectRelationalMapper'); // singleton
                $dataMapper->persistAll();
        }
 
index e0ab954..4529867 100644 (file)
@@ -77,28 +77,25 @@ class TX_EXTMVC_Dispatcher {
         * @return String $content The processed content
         */
        public function dispatch($content, $configuration) {
-
-               // TODO Remove debug statement
-               // $start_time = microtime(TRUE);
-
                $parameters = t3lib_div::_GET();
-               // TODO We should refuse to let the client change the plugins behaviour by adding "&action=show" to the url
-               $extensionKey = isset($parameters['extension']) ? stripslashes($parameters['extension']) : $configuration['extension'];
-               $controllerName = isset($parameters['controller']) ? stripslashes($parameters['controller']) : $configuration['controller'];
-               $actionName = isset($parameters['action']) ? stripslashes($parameters['action']) : $configuration['action'];
-
-               $request = t3lib_div::makeInstance('TX_EXTMVC_Web_Request');
-               $request->setControllerExtensionKey($extensionKey);
-               $request->setControllerName($controllerName);
-               $request->setControllerActionName($actionName);
-
-               $controllerObjectName = $request->getControllerObjectName();
-               $controller = t3lib_div::makeInstance($controllerObjectName);
+               $extensionKey = $configuration['extension'];
+               $controllerName = $configuration['controller'];
+               $allowedActions = t3lib_div::trimExplode(',', $configuration['allowedActions']);
+               if (isset($parameters['action']) && in_array($parameters['action'], $allowedActions)) {
+                       $actionName = stripslashes($parameters['action']);
+               } else {
+                       $actionName = $configuration['action'];
+               }
+               if (empty($extensionKey) || empty($controllerName) || empty($allowedActions)) {
+                       throw new Exception('Could not dispatch the request. Please configure your plugin in the TS Setup.', 1237879677);
+               }
 
-               if (!$controller instanceof TX_EXTMVC_Controller_AbstractController) throw new TX_EXTMVC_Exception_InvalidController('Invalid controller "' . $controllerObjectName . '". The controller must be a valid request handling controller.', 1202921619);
+               $request = $this->buildRequest($extensionKey, $controllerName, $actionName);
+               $controller = t3lib_div::makeInstance($request->getControllerObjectName());
+               if (!$controller instanceof TX_EXTMVC_Controller_AbstractController) throw new TX_EXTMVC_Exception_InvalidController('Invalid controller "' . $request->getControllerObjectName() . '". The controller must be a valid request handling controller.', 1202921619);
 
                if (!$controller->isCachableAction($actionName) && $this->cObj->getUserObjectType() === tslib_cObj::OBJECTTYPE_USER) {
-                       // FIXME Caching does nort work because it's by default a USER object, so the dispatcher is never called
+                       // FIXME Caching does not work because it's by default a USER object, so the dispatcher is never called
                        // SK: does caching already work?
                        $this->cObj->convertToUserIntObject();
                        return $content;
@@ -110,43 +107,50 @@ class TX_EXTMVC_Dispatcher {
                foreach (t3lib_div::GParrayMerged('tx_' . strtolower($extensionKey)) as $key => $value) {
                        $request->setArgument($key, $value);
                }
-               $request->setRequestURI(t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'));
-               $request->setBaseURI(t3lib_div::getIndpEnv('TYPO3_SITE_URL'));
-               $response = t3lib_div::makeInstance('TX_EXTMVC_Web_Response');
 
-               $configurationSources = array();
-               $configurationSources[] = t3lib_div::makeInstance('TX_EXTMVC_Configuration_Source_TS');
-               if (!empty($this->cObj->data['pi_flexform'])) {
-                       $configurationSource = t3lib_div::makeInstance('TX_EXTMVC_Configuration_Source_FlexForm');
-                       $configurationSource->setFlexFormContent($this->cObj->data['pi_flexform']);
-                       $configurationSources[] = $configurationSource;
-               }
-               $configurationManager = t3lib_div::makeInstance('TX_EXTMVC_Configuration_Manager', $configurationSources);
-               $configurationManager->loadGlobalSettings($extensionKey);
-               $configurationManager = t3lib_div::makeInstance('TX_EXTMVC_Configuration_Manager');
-               $controller->injectSettings($configurationManager->getSettings($extensionKey));
+               $response = t3lib_div::makeInstance('TX_EXTMVC_Web_Response');
+               $controller->injectSettings($this->getSettings($extensionKey));
 
                $session = t3lib_div::makeInstance('TX_EXTMVC_Persistence_Session');
                try {
                        $controller->processRequest($request, $response);
                } catch (TX_EXTMVC_Exception_StopAction $ignoredException) {
                }
+               // debug($session);
                $session->commit();
                $session->clear();
                
                if (count($response->getAdditionalHeaderData()) > 0) {
                        $GLOBALS['TSFE']->additionalHeaderData[$request->getControllerExtensionKey()] = implode("\n", $response->getAdditionalHeaderData());
                }
-
-               // TODO Remove debug statements
-               // $end_time = microtime(TRUE);
-               // debug($end_time - $start_time, -1);
-
                // TODO Handle $response->getStatus()
                // SK: Call sendHeaders() on the response
                // JR: I don't think we need this, because the header will be sent by TYPO3
                return $response->getContent();
        }
+       
+       protected function getSettings($extensionKey) {
+               $configurationSources = array();
+               $configurationSources[] = t3lib_div::makeInstance('TX_EXTMVC_Configuration_Source_TS');
+               if (!empty($this->cObj->data['pi_flexform'])) {
+                       $configurationSource = t3lib_div::makeInstance('TX_EXTMVC_Configuration_Source_FlexForm');
+                       $configurationSource->setFlexFormContent($this->cObj->data['pi_flexform']);
+                       $configurationSources[] = $configurationSource;
+               }
+               $configurationManager = t3lib_div::makeInstance('TX_EXTMVC_Configuration_Manager', $configurationSources);
+               $configurationManager->loadGlobalSettings($extensionKey);
+               return $configurationManager->getSettings($extensionKey);
+       }
+       
+       protected function buildRequest($extensionKey, $controllerName, $actionName) {
+               $request = t3lib_div::makeInstance('TX_EXTMVC_Web_Request');
+               $request->setControllerExtensionKey($extensionKey);
+               $request->setControllerName($controllerName);
+               $request->setControllerActionName($actionName);
+               $request->setRequestURI(t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'));
+               $request->setBaseURI(t3lib_div::getIndpEnv('TYPO3_SITE_URL'));
+               return $request;
+       }
 
        /**
         * Loads php files containing classes or interfaces found in the classes directory of