[!!!][~TASK] Extbase (Utility): Moved configureDispatcher() and registerPlugin()...
authorJochen Rau <j.rau@web.de>
Mon, 10 Aug 2009 23:20:05 +0000 (23:20 +0000)
committerJochen Rau <j.rau@web.de>
Mon, 10 Aug 2009 23:20:05 +0000 (23:20 +0000)
[!!!][~BUGFIX] Extbase (Persistence): Restructured responsibilities of Repository and Session. You don't need to register reconstituted, added, and removed objects in your Repositories anymore. Please remove all occurrences of $this->persistenceManager->getSession()->register*Object($object). Resolves #3916.
[+FEATURE] Extbase (Utility): Added registerModule() to Tx_Extbase_Utility_Extension. Related to #3995.
[+TASK] Extbase (DomainModel): Added (internal) method _hasProperty() to AbstractDomainModel.
[~TASK] Extbase (Property): Improved mapping of properties (not finished yet).
[~BUGFIX] Extbase (MVC): The RequestBuilder now merges $_GET and $_POST using t3lib_div::_GPmerged(). It expects the $_POST parameter to be namespaced now. Resolves #3316.
[+FEATURE] Extbase(Reflection): Backported the ClassSchema from FLOW3. This was necessary to support the Property Mapper.

29 files changed:
typo3/sysext/extbase/Classes/Dispatcher.php
typo3/sysext/extbase/Classes/DomainObject/AbstractDomainObject.php
typo3/sysext/extbase/Classes/MVC/Controller/AbstractController.php
typo3/sysext/extbase/Classes/MVC/Controller/Argument.php
typo3/sysext/extbase/Classes/MVC/Request.php
typo3/sysext/extbase/Classes/MVC/Web/RequestBuilder.php
typo3/sysext/extbase/Classes/MVC/Web/Routing/URIBuilder.php
typo3/sysext/extbase/Classes/Persistence/Backend.php
typo3/sysext/extbase/Classes/Persistence/BackendInterface.php
typo3/sysext/extbase/Classes/Persistence/IdentityMap.php
typo3/sysext/extbase/Classes/Persistence/LazyLoadingProxy.php
typo3/sysext/extbase/Classes/Persistence/Manager.php
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMap.php
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapper.php
typo3/sysext/extbase/Classes/Persistence/Repository.php
typo3/sysext/extbase/Classes/Persistence/RepositoryInterface.php
typo3/sysext/extbase/Classes/Persistence/Session.php
typo3/sysext/extbase/Classes/Persistence/Storage/Typo3DbBackend.php
typo3/sysext/extbase/Classes/Property/Mapper.php
typo3/sysext/extbase/Classes/Reflection/ClassSchema.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/Reflection/Exception/InvalidPropertyType.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/Reflection/ObjectAccess.php
typo3/sysext/extbase/Classes/Reflection/Service.php
typo3/sysext/extbase/Classes/Utility/Extension.php
typo3/sysext/extbase/Classes/Utility/Plugin.php [deleted file]
typo3/sysext/extbase/Tests/MVC/Web/RequestBuilder_testcase.php
typo3/sysext/extbase/Tests/Utility/Plugin_testcase.php
typo3/sysext/extbase/ext_autoload.php
typo3/sysext/extbase/ext_localconf.php

index 788dc62..f5b3f34 100644 (file)
@@ -139,11 +139,12 @@ class Tx_Extbase_Dispatcher {
                if (!$controller instanceof Tx_Extbase_MVC_Controller_ControllerInterface) {
                        throw new Tx_Extbase_MVC_Exception_InvalidController('Invalid controller "' . $request->getControllerObjectName() . '". The controller must implement the Tx_Extbase_MVC_Controller_ControllerInterface.', 1202921619);
                }
+               self::$reflectionService = t3lib_div::makeInstance('Tx_Extbase_Reflection_Service');
                $propertyMapper = t3lib_div::makeInstance('Tx_Extbase_Property_Mapper');
+               $propertyMapper->injectReflectionService(self::$reflectionService);
                $controller->injectPropertyMapper($propertyMapper);
                $controller->injectSettings($this->configurationManager->getSettings($request->getControllerExtensionName()));
                $cacheManager = t3lib_div::makeInstance('t3lib_cache_Manager');
-               self::$reflectionService = t3lib_div::makeInstance('Tx_Extbase_Reflection_Service');
                try {
                        self::$reflectionService->setCache($cacheManager->getCache('cache_extbase_reflection'));
                } catch (t3lib_cache_exception_NoSuchCache $exception) {
@@ -175,25 +176,29 @@ class Tx_Extbase_Dispatcher {
         */
        public static function getPersistenceManager() {
                if (self::$persistenceManager === NULL) {
-                       $queryFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory'); // singleton
-
                        $dataMapper = t3lib_div::makeInstance('Tx_Extbase_Persistence_Mapper_DataMapper'); // singleton
 
                        $storageBackend = t3lib_div::makeInstance('Tx_Extbase_Persistence_Storage_Typo3DbBackend', $GLOBALS['TYPO3_DB']); // singleton
                        $storageBackend->injectDataMapper($dataMapper);
 
+                       $qomFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QOM_QueryObjectModelFactory', $storageBackend, $dataMapper);
+                       
                        $persistenceSession = t3lib_div::makeInstance('Tx_Extbase_Persistence_Session'); // singleton
 
                        $persistenceBackend = t3lib_div::makeInstance('Tx_Extbase_Persistence_Backend', $persistenceSession, $storageBackend); // singleton
                        $persistenceBackend->injectDataMapper($dataMapper);
                        $persistenceBackend->injectIdentityMap(t3lib_div::makeInstance('Tx_Extbase_Persistence_IdentityMap'));
-                       $persistenceBackend->injectQOMFactory(t3lib_div::makeInstance('Tx_Extbase_Persistence_QOM_QueryObjectModelFactory', $storageBackend, $dataMapper));
+                       $persistenceBackend->injectQueryFactory(t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory'));
+                       $persistenceBackend->injectQOMFactory($qomFactory);
                        $persistenceBackend->injectValueFactory(t3lib_div::makeInstance('Tx_Extbase_Persistence_ValueFactory'));
 
+                       $objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_Manager'); // singleton
+                       
                        $persistenceManager = t3lib_div::makeInstance('Tx_Extbase_Persistence_Manager'); // singleton
                        $persistenceManager->injectBackend($persistenceBackend);
                        $persistenceManager->injectSession($persistenceSession);
-
+                       $persistenceManager->injectObjectManager($objectManager);
+                       
                        self::$persistenceManager = $persistenceManager;
                }
 
@@ -222,7 +227,7 @@ class Tx_Extbase_Dispatcher {
                // TODO Make a registry for Extbase classes
                //$starttime = microtime(true);
                $classNameParts = explode('_', $className, 3);
-               $extensionKey = Tx_Extbase_Utility_Plugin::convertCamelCaseToLowerCaseUnderscored($classNameParts[1]);
+               $extensionKey = Tx_Extbase_Utility_Extension::convertCamelCaseToLowerCaseUnderscored($classNameParts[1]);
                if (t3lib_extMgm::isLoaded($extensionKey)) {
                        $classFilePathAndName = t3lib_extMgm::extPath($extensionKey) . 'Classes/' . strtr($classNameParts[2], '_', '/') . '.php';
                        if (file_exists($classFilePathAndName)) {
index 4eb0f3b..1d9f94e 100644 (file)
@@ -91,7 +91,7 @@ abstract class Tx_Extbase_DomainObject_AbstractDomainObject implements Tx_Extbas
         * @return void
         */
        public function _setProperty($propertyName, $propertyValue) {
-               if (property_exists($this, $propertyName)) {
+               if ($this->_hasProperty($propertyName)) {
                        $this->$propertyName = $propertyValue;
                        return TRUE;
                }
@@ -117,6 +117,16 @@ abstract class Tx_Extbase_DomainObject_AbstractDomainObject implements Tx_Extbas
                unset($properties['_cleanProperties']);
                return $properties;
        }
+       
+       /**
+        * Returns the property value of the given property name. Only for internal use.
+        *
+        * @return boolean TRUE bool true if the property exists, FALSE if it doesn't exist or
+        * NULL in case of an error.
+        */
+       public function _hasProperty($propertyName) {
+               return property_exists($this, $propertyName);
+       }
 
        /**
         * Returns TRUE if the object is new (the uid was not set, yet). Only for internal use
index 5c11d89..07a3af6 100755 (executable)
@@ -259,7 +259,7 @@ abstract class Tx_Extbase_MVC_Controller_AbstractController implements Tx_Extbas
                if ($controllerName === NULL) {
                        $controllerName = $this->request->getControllerName();
                }
-               if ($pageUid === NULL) {
+               if ($pageUid === NULL && isset($GLOBALS['TSFE'])) {
                        $pageUid = $GLOBALS['TSFE']->id;
                }
 
index 8157291..afec9dc 100644 (file)
 class Tx_Extbase_MVC_Controller_Argument {
 
        /**
-        * @var Tx_Extbase_Persistence_ManagerInterface
-        */
-       protected $persistenceManager;
-
-       /**
         * @var Tx_Extbase_Persistence_QueryFactory
         */
        protected $queryFactory;
@@ -114,6 +109,7 @@ class Tx_Extbase_MVC_Controller_Argument {
         */
        public function __construct($name, $dataType = 'Text') {
                $this->propertyMapper = t3lib_div::makeInstance('Tx_Extbase_Property_Mapper');
+               $this->propertyMapper->injectReflectionService(t3lib_div::makeInstance('Tx_Extbase_Reflection_Service'));
                if (!is_string($name) || strlen($name) < 1) throw new InvalidArgumentException('$name must be of type string, ' . gettype($name) . ' given.', 1187951688);
                $this->name = $name;
                if (is_array($dataType)) {
index 20f0396..4b06212 100644 (file)
@@ -181,7 +181,7 @@ class Tx_Extbase_MVC_Request {
         * @api
         */
        public function getControllerExtensionKey() {
-               return Tx_Extbase_Utility_Plugin::convertCamelCaseToLowerCaseUnderscored($this->controllerExtensionName);
+               return Tx_Extbase_Utility_Extension::convertCamelCaseToLowerCaseUnderscored($this->controllerExtensionName);
        }
 
        /**
index 4b7ff95..8d7e224 100755 (executable)
@@ -108,7 +108,7 @@ class Tx_Extbase_MVC_Web_RequestBuilder {
         * @return Tx_Extbase_MVC_Web_Request The web request as an object
         */
        public function build() {
-               $parameters = t3lib_div::_GET('tx_' . strtolower($this->extensionName) . '_' . strtolower($this->pluginName));
+               $parameters = t3lib_div::_GPmerged('tx_' . strtolower($this->extensionName) . '_' . strtolower($this->pluginName));
 
                if (is_string($parameters['controller']) && array_key_exists($parameters['controller'], $this->allowedControllerActions)) {
                        $controllerName = filter_var($parameters['controller'], FILTER_SANITIZE_STRING);
@@ -131,24 +131,11 @@ class Tx_Extbase_MVC_Web_RequestBuilder {
                $request->setRequestURI(t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'));
                $request->setBaseURI(t3lib_div::getIndpEnv('TYPO3_SITE_URL'));
                $request->setMethod((isset($_SERVER['REQUEST_METHOD'])) ? $_SERVER['REQUEST_METHOD'] : NULL);
-               $GET = t3lib_div::_GET('tx_' . strtolower($this->extensionName) . '_' . strtolower($this->pluginName));
-               if (is_array($GET)) {
-                       foreach ($GET as $argumentName => $argumentValue) {
-                               $request->setArgument($argumentName, $argumentValue);
-                       }
-               }
-               // POST
-               if ($request->getMethod() === 'POST') {
-                       if (is_array($_POST)) {
-                               foreach ($_POST as $argumentName => $argumentValue) {
-                                       $request->setArgument($argumentName, $argumentValue);
-                               }
-                       }
+
+               foreach ($parameters as $argumentName => $argumentValue) {
+                       $request->setArgument($argumentName, $argumentValue);
                }
-               // FIXME The following lines are the preferred solution to fetch the GET and POST arguments. They can't be used until Fluid is patched to namespace POST arguments
-//             foreach (t3lib_div::_GPmerged('tx_' . strtolower($this->extensionName) . '_' . strtolower($this->pluginName)) as $argumentName => $argumentValue) {
-//                     $request->setArgument($argumentName, $argumentValue);
-//             }
+
                return $request;
        }
 
index 6bafa1a..e9246db 100644 (file)
@@ -126,7 +126,11 @@ class Tx_Extbase_MVC_Web_Routing_URIBuilder {
         */
        public function typolinkURI($pageUid = NULL, array $arguments = array(), $pageType = 0, $noCache = FALSE, $useCacheHash = TRUE, $section = '', $linkAccessRestrictedPages = FALSE, $absolute = FALSE) {
                if ($pageUid === NULL) {
-                       $pageUid = $GLOBALS['TSFE']->id;
+                       if (isset($GLOBALS['TSFE'])) {
+                               $pageUid = $GLOBALS['TSFE']->id;
+                       } else {
+                               $pageUid = 0;
+                       }
                }
 
                $typolinkConfiguration = array();
index 7f31691..f6fa00f 100644 (file)
@@ -51,6 +51,11 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
        protected $identityMap;
 
        /**
+        * @var Tx_Extbase_Persistence_QueryFactoryInterface
+        */
+       protected $queryFactory;
+
+       /**
         * @var Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface
         */
        protected $QOMFactory;
@@ -112,6 +117,16 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
        }
 
        /**
+        * Injects the QueryFactory
+        *
+        * @param Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory
+        * @return void
+        */
+       public function injectQueryFactory(Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory) {
+               $this->queryFactory = $queryFactory;
+       }
+       
+       /**
         * Injects the QueryObjectModelFactory
         *
         * @param Tx_Extbase_Persistence_QOM_QueryObjectModelFactoryInterface $dataMapper
@@ -192,6 +207,28 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
        }
 
        /**
+        * Returns the object with the (internal) identifier, if it is known to the
+        * backend. Otherwise NULL is returned.
+        *
+        * @param string $identifier
+        * @param string $className
+        * @return object The object for the identifier if it is known, or NULL
+        */
+       public function getObjectByIdentifier($identifier, $className) {
+               if ($this->identityMap->hasIdentifier($identifier, $className)) {
+                       return $this->identityMap->getObjectByIdentifier($identifier, $className);
+               } else {
+                       $query = $this->queryFactory->create($className);
+                       $result = $query->matching($query->withUid($uid))->execute();
+                       $object = NULL;
+                       if (count($result) > 0) {
+                               $object = current($result);
+                       }
+                       return $object;                 
+               }
+       }
+
+       /**
         * Checks if the given object has ever been persisted.
         *
         * @param object $object The object to check
index 66765d4..446440d 100644 (file)
@@ -67,6 +67,16 @@ interface Tx_Extbase_Persistence_BackendInterface {
        public function getIdentifierByObject($object);
 
        /**
+        * Returns the object with the (internal) identifier, if it is known to the
+        * backend. Otherwise NULL is returned.
+        *
+        * @param string $identifier
+        * @param string $className
+        * @return object The object for the identifier if it is known, or NULL
+        */
+       public function getObjectByIdentifier($identifier, $className);
+
+       /**
         * Checks if the given object has ever been persisted.
         *
         * @param object $object The object to check
index e4783f6..2cb6c25 100644 (file)
 ***************************************************************/
 
 /**
- * An Idetity Map for Domain Objects
+ * An identity mapper to map nodes to objects
  *
- * @package Extbase
- * @subpackage Persistence
- * @version $ID:$
+ * @version $Id$
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ * @see \F3\TYPO3CR\FLOW3\Persistence\DataMapper, \F3\TYPO3CR\FLOW3\Persistence\Backend
  */
 class Tx_Extbase_Persistence_IdentityMap {
 
@@ -42,10 +42,12 @@ class Tx_Extbase_Persistence_IdentityMap {
        /**
         * @var array
         */
-       protected $uidMap = array();
+       protected $uuidMap = array();
 
        /**
         * Constructs a new Identity Map
+        *
+        * @author Karsten Dambekalns <karsten@typo3.org>
         */
        public function __construct() {
                $this->objectMap = new Tx_Extbase_Persistence_ObjectStorage();
@@ -56,35 +58,36 @@ class Tx_Extbase_Persistence_IdentityMap {
         *
         * @param object $object
         * @return boolean
+        * @author Karsten Dambekalns <karsten@typo3.org>
         */
        public function hasObject($object) {
                return $this->objectMap->contains($object);
        }
 
        /**
-        * Checks whether the given uiduid is known to the identity map
+        * Checks whether the given UUID is known to the identity map
         *
+        * @param string $uuid
         * @param string $className
-        * @param string $uid
         * @return boolean
         */
-       public function hasUid($className, $uid) {
-               if (is_array($this->uidMap[$className])) {
-                       return array_key_exists($uid, $this->uidMap[$className]);
+       public function hasIdentifier($uuid, $className) {
+               if (is_array($this->uuidMap[$className])) {
+                       return array_key_exists($uuid, $this->uuidMap[$className]);
                } else {
                        return FALSE;
                }
        }
 
        /**
-        * Returns the object for the given uid
+        * Returns the object for the given UUID
         *
+        * @param string $uuid
         * @param string $className
-        * @param string $uid
         * @return object
         */
-       public function getObjectByUid($className, $uid) {
-               return $this->uidMap[$className][$uid];
+       public function getObjectByIdentifier($uuid, $className) {
+               return $this->uuidMap[$className][$uuid];
        }
 
        /**
@@ -92,8 +95,13 @@ class Tx_Extbase_Persistence_IdentityMap {
         *
         * @param object $object
         * @return string
+        * @author Karsten Dambekalns <karsten@typo3.org>
         */
        public function getIdentifierByObject($object) {
+               if (!is_object($object)) throw new InvalidArgumentException('Object expected, ' . gettype($object) . ' given.', 1246892972);
+               if (!isset($this->objectMap[$object])) {
+                       throw new Tx_Extbase_Persisitence_Exception_UnknownObjectException('The given object (class: ' . get_class($object) . ') is not registered in this Identity Map.', 1246892970);
+               }
                return $this->objectMap[$object];
        }
 
@@ -101,11 +109,12 @@ class Tx_Extbase_Persistence_IdentityMap {
         * Register a node identifier for an object
         *
         * @param object $object
-        * @param string $uid
+        * @param string $uuid
+        * @author Karsten Dambekalns <karsten@typo3.org>
         */
-       public function registerObject($object, $uid) {
-               $this->objectMap[$object] = $uid;
-               $this->uidMap[get_class($object)][$uid] = $object;
+       public function registerObject($object, $uuid) {
+               $this->objectMap[$object] = $uuid;
+               $this->uuidMap[get_class($object)][$uuid] = $object;
        }
 
        /**
@@ -113,12 +122,12 @@ class Tx_Extbase_Persistence_IdentityMap {
         *
         * @param string $object
         * @return void
+        * @author Karsten Dambekalns <karsten@typo3.org>
         */
        public function unregisterObject($object) {
-               unset($this->uidMap[get_class($object)][$this->objectMap[$object]]);
+               unset($this->uuidMap[get_class($object)][$this->objectMap[$object]]);
                $this->objectMap->detach($object);
        }
 
 }
-
 ?>
\ No newline at end of file
index 0622561..6703ccd 100644 (file)
@@ -90,11 +90,18 @@ class Tx_Extbase_Persistence_LazyLoadingProxy {
         * @return object The instance (hopefully) returned
         */
        public function _loadRealInstance() {
-               $dataMapper = Tx_Extbase_Dispatcher::getPersistenceManager()->getBackend()->getDataMapper();
-               $result = $dataMapper->fetchRelatedObjects($this->parentObject, $this->propertyName, $this->fieldValue, $this->columnMap);
-               $this->parentObject->_setProperty($this->propertyName, $result);
-               $this->parentObject->_memorizeCleanState($this->propertyName);
-               return $result;
+               // this check safeguards against a proxy being activated multiple times
+               // usually that does not happen, but if the proxy is held from outside
+               // it's parent... the result would be weird.
+               if ($this->parentObject->_getProperty($this->propertyName) instanceof Tx_Extbase_Persistence_LazyLoadingProxy) {
+                       $dataMapper = Tx_Extbase_Dispatcher::getPersistenceManager()->getBackend()->getDataMapper();
+                       $realInstance = $dataMapper->fetchRelatedObjects($this->parentObject, $this->propertyName, $this->fieldValue, $this->columnMap);
+                       $this->parentObject->_setProperty($this->propertyName, $realInstance);
+                       $this->parentObject->_memorizeCleanState($this->propertyName);
+                       return $realInstance;
+               } else {
+                       return $this->parentObject->_getProperty($this->propertyName);
+               }
        }
 
        /**
index 1bc4820..49f36d2 100644 (file)
@@ -46,6 +46,18 @@ class Tx_Extbase_Persistence_Manager implements Tx_Extbase_Persistence_ManagerIn
        protected $session;
 
        /**
+        * @var Tx_Extbase_Object_ManagerInterface
+        */
+       protected $objectManager;
+
+       /**
+        * This is an array of registered repository class names.
+        *
+        * @var array
+        */
+       protected $repositoryClassNames = array();
+
+       /**
         * Injects the Persistence Backend
         *
         * @param Tx_Extbase_Persistence_BackendInterface $backend The persistence backend
@@ -67,6 +79,16 @@ class Tx_Extbase_Persistence_Manager implements Tx_Extbase_Persistence_ManagerIn
        public function injectSession(Tx_Extbase_Persistence_Session $session) {
                $this->session = $session;
        }
+       
+       /**
+        * Injects the object manager
+        *
+        * @param Tx_Extbase_Object_ManagerInterface $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
 
        /**
         * Returns the current persistence session
@@ -86,6 +108,25 @@ class Tx_Extbase_Persistence_Manager implements Tx_Extbase_Persistence_ManagerIn
        public function getBackend() {
                return $this->backend;
        }
+       
+       /**
+        * Registers a repository
+        *
+        * @param string $className The class name of the repository to be reigistered
+        * @return void
+        */
+       public function registerRepositoryClassName($className) {
+               $this->repositoryClassNames[] = $className;
+       }
+
+       /**
+        * Returns all repository class names
+        *
+        * @return array An array holding the registered repository class names
+        */
+       public function getRepositoryClassNames() {
+               return $this->repositoryClassNames;
+       }
 
        /**
         * Commits new objects and changes to objects in the current persistence
@@ -96,14 +137,32 @@ class Tx_Extbase_Persistence_Manager implements Tx_Extbase_Persistence_ManagerIn
         */
        public function persistAll() {
                $aggregateRootObjects = new Tx_Extbase_Persistence_ObjectStorage();
-               $aggregateRootObjects->addAll($this->session->getAddedObjects());
-               $aggregateRootObjects->addAll($this->session->getReconstitutedObjects());
+               $removedObjects = new Tx_Extbase_Persistence_ObjectStorage();
 
-               $removedObjects = $this->session->getRemovedObjects();
+                       // fetch and inspect objects from all known repositories
+               $repositoryClassNames = $this->getRepositoryClassNames();
+               foreach ($repositoryClassNames as $repositoryClassName) {
+                       $repository = $this->objectManager->getObject($repositoryClassName);
+                       $aggregateRootObjects->addAll($repository->getAddedObjects());
+                       $removedObjects->addAll($repository->getRemovedObjects());
+               }
 
+               $aggregateRootObjects->addAll($this->session->getReconstitutedObjects());
+
+                       // hand in only aggregate roots, leaving handling of subobjects to
+                       // the underlying storage layer
                $this->backend->setAggregateRootObjects($aggregateRootObjects);
                $this->backend->setDeletedObjects($removedObjects);
                $this->backend->commit();
+
+                       // this needs to unregister more than just those, as at least some of
+                       // the subobjects are supposed to go away as well...
+                       // OTOH those do no harm, changes to the unused ones should not happen,
+                       // so all they do is eat some memory.
+               foreach($removedObjects as $removedObject) {
+                       $this->session->unregisterReconstitutedObject($removedObject);
+               }
        }
+               
 }
 ?>
\ No newline at end of file
index 0dec360..55bae73 100644 (file)
@@ -119,7 +119,7 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
                                if (!empty($mapping[$columnName]['mapOnProperty'])) {
                                        $propertyName = $mapping[$columnName]['mapOnProperty'];
                                } else {
-                                       $propertyName = Tx_Extbase_Utility_Plugin::convertUnderscoredToLowerCamelCase($columnName);
+                                       $propertyName = Tx_Extbase_Utility_Extension::convertUnderscoredToLowerCamelCase($columnName);
                                }
                                if (isset($mapping[$columnName]['foreignClass']) && !isset($columnConfiguration['config']['foreign_class'])) {
                                        $columnConfiguration['config']['foreign_class'] = $mapping[$columnName]['foreignClass'];
@@ -273,7 +273,7 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         */
        public function addColumn($columnName, $propertyName = '', $propertyType = Tx_Extbase_Persistence_PropertyType::STRING, $typeOfRelation = Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_NONE) {
                if (empty($propertyName)) {
-                       $propertyName = Tx_Extbase_Utility_Plugin::convertUnderscoredToLowerCamelCase($columnName);
+                       $propertyName = Tx_Extbase_Utility_Extension::convertUnderscoredToLowerCamelCase($columnName);
                }
 
                $columnMap = new Tx_Extbase_Persistence_Mapper_ColumnMap($columnName, $propertyName);
index 7f28912..c67cc6a 100644 (file)
@@ -42,6 +42,11 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        protected $QOMFactory;
 
        /**
+        * @var Tx_Extbase_Persistence_Session
+        */
+       protected $persistenceSession;
+
+       /**
         * A reference to the page select object providing methods to perform language and work space overlays
         *
         * @var t3lib_pageSelect
@@ -93,6 +98,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         */
        public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
                $this->QOMFactory = $persistenceManager->getBackend()->getQOMFactory();
+               $this->persistenceSession = $persistenceManager->getSession();
        }
 
        /**
@@ -117,13 +123,14 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         * @return object
         */
        protected function mapSingleRow($className, Tx_Extbase_Persistence_RowInterface $row) {
-               if ($this->identityMap->hasUid($className, $row['uid'])) {
-                       $object = $this->identityMap->getObjectByUid($className, $row['uid']);
+               if ($this->identityMap->hasIdentifier($row['uid'], $className)) {
+                       $object = $this->identityMap->getObjectByIdentifier($row['uid'], $className);
                } else {
                        $object = $this->createEmptyObject($className);
                        $this->thawProperties($object, $row);
                        $this->identityMap->registerObject($object, $object->getUid());
                        $object->_memorizeCleanState();
+                       $this->persistenceSession->registerReconstitutedObject($object);
                }
                return $object;
        }
@@ -342,7 +349,6 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         * @return string The selector name
         */
        public function convertClassNameToTableName($className) {
-               
                return $this->getDataMap($className)->getTableName();
        }
 
@@ -363,7 +369,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
                                }
                        }
                }
-               return Tx_Extbase_Utility_Plugin::convertCamelCaseToLowerCaseUnderscored($propertyName);
+               return Tx_Extbase_Utility_Extension::convertCamelCaseToLowerCaseUnderscored($propertyName);
        }
        
 }
index b0d3411..601e3d5 100644 (file)
 class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_RepositoryInterface, t3lib_Singleton {
 
        /**
+        * Objects of this repository
+        *
+        * @var Tx_Extbase_Persistence_ObjectStorage
+        */
+       protected $addedObjects;
+
+       /**
+        * Objects removed but not found in $this->addedObjects at removal time
+        *
+        * @var Tx_Extbase_Persistence_ObjectStorage
+        */
+       protected $removedObjects;
+
+       /**
         * @var Tx_Extbase_Persistence_QueryFactoryInterface
         */
        protected $queryFactory;
@@ -54,9 +68,12 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
         *
         */
        public function __construct() {
+               $this->addedObjects = new Tx_Extbase_Persistence_ObjectStorage();
+               $this->removedObjects = new Tx_Extbase_Persistence_ObjectStorage();
+               $this->queryFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory'); // singleton
                $this->persistenceManager = Tx_Extbase_Dispatcher::getPersistenceManager();
+               $this->persistenceManager->registerRepositoryClassName(get_class($this));
                $this->objectType = str_replace(array('_Repository_', 'Repository'), array('_Model_', ''), $this->getRepositoryClassName());
-               $this->queryFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory'); // singleton
        }
 
        /**
@@ -67,9 +84,12 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
         * @api
         */
        public function add($object) {
-       // SK: Why is this commented out?
-//             if (!is_object($object) || !($object instanceof $this->aggregateRootClassName)) throw new Tx_Extbase_Persistence_Exception_InvalidClass('The class "' . get_class($object) . '" is not supported by the repository.');
-               $this->persistenceManager->getSession()->registerAddedObject($object);
+               if (!($object instanceof $this->objectType)) {
+                       throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The object given to add() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
+               }
+
+               $this->addedObjects->attach($object);
+               $this->removedObjects->detach($object);
        }
 
        /**
@@ -80,10 +100,15 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
         * @api
         */
        public function remove($object) {
+               if (!($object instanceof $this->objectType)) {
+                       throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The object given to add() was not of the type (' . $this->objectType . ') this repository manages.', 1248363335);
+               }
 
-       // SK: Why is this commented out?
-//             if (!is_object($object) || !($object instanceof $this->aggregateRootClassName)) throw new Tx_Extbase_Persistence_Exception_InvalidClass('The class "' . get_class($object) . '" is not supported by the repository.');
-               $this->persistenceManager->getSession()->registerRemovedObject($object);
+               if ($this->addedObjects->contains($object)) {
+                       $this->addedObjects->detach($object);
+               } else {
+                       $this->removedObjects->attach($object);
+               }
        }
 
        /**
@@ -95,17 +120,32 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
         * @api
         */
        public function replace($existingObject, $newObject) {
-               // TODO: Update this method from FLOW3
+               if (!($existingObject instanceof $this->objectType)) {
+                       throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The existing object given to replace was not of the type (' . $this->objectType . ') this repository manages.', 1248363434);
+               }
+               if (!($newObject instanceof $this->objectType)) {
+                       throw new Tx_Extbase_Persistence_Exception_IllegalObjectType('The new object given to replace was not of the type (' . $this->objectType . ') this repository manages.', 1248363439);
+               }
+               
                $backend = $this->persistenceManager->getBackend();
                $session = $this->persistenceManager->getSession();
-               $uid = $backend->getIdentifierByObject($existingObject);
-               if ($uid !== NULL) {
+               $uuid = $backend->getIdentifierByObject($existingObject);
+               if ($uuid !== NULL) {
                        $backend->replaceObject($existingObject, $newObject);
                        $session->unregisterReconstitutedObject($existingObject);
                        $session->registerReconstitutedObject($newObject);
+
+                       if ($this->removedObjects->contains($existingObject)) {
+                               $this->removedObjects->detach($existingObject);
+                               $this->removedObjects->attach($newObject);
+                       }
+               } elseif ($this->addedObjects->contains($existingObject)) {
+                       $this->addedObjects->detach($existingObject);
+                       $this->addedObjects->attach($newObject);
                } else {
-                       throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "existing object" is unknown to the repository.', 1238068475);
+                       throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "existing object" is unknown to the persistence backend.', 1238068475);
                }
+               
        }
 
        /**
@@ -127,7 +167,29 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
                        throw new Tx_Extbase_Persistence_Exception_UnknownObject('The "modified object" is does not have an existing counterpart in this repository.', 1249479819);
                }
        }
+       
+       /**
+        * Returns all addedObjects that have been added to this repository with add().
+        *
+        * This is a service method for the persistence manager to get all addedObjects
+        * added to the repository. Those are only objects *added*, not objects
+        * fetched from the underlying storage.
+        *
+        * @return Tx_Extbase_Persistence_ObjectStorage the objects
+        */
+       public function getAddedObjects() {
+               return $this->addedObjects;
+       }
 
+       /**
+        * Returns an Tx_Extbase_Persistence_ObjectStorage with objects remove()d from the repository
+        * that had been persisted to the storage layer before.
+        *
+        * @return Tx_Extbase_Persistence_ObjectStorage the objects
+        */
+       public function getRemovedObjects() {
+               return $this->removedObjects;
+       }
 
        /**
         * Returns all objects of this repository
@@ -137,7 +199,6 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
         */
        public function findAll() {
                $result = $this->createQuery()->execute();
-               $this->persistenceManager->getSession()->registerReconstitutedObjects($result);
                return $result;
        }
 
@@ -155,7 +216,6 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
                $object = NULL;
                if (count($result) > 0) {
                        $object = current($result);
-                       $this->persistenceManager->getSession()->registerReconstitutedObject($object);
                }
                return $object;
        }
@@ -186,7 +246,6 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
                        $query = $this->createQuery();
                        $result = $query->matching($query->equals($propertyName, $arguments[0]))
                                ->execute();
-                       $this->persistenceManager->getSession()->registerReconstitutedObjects($result);
                        return $result;
                } elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
                        $propertyName = strtolower(substr(substr($methodName, 9), 0, 1) ) . substr(substr($methodName, 9), 1);
@@ -197,8 +256,6 @@ class Tx_Extbase_Persistence_Repository implements Tx_Extbase_Persistence_Reposi
                        $object = NULL;
                        if (count($result) > 0) {
                                $object = current($result);
-                               // SK: registerReconstitutedObject() needs to be called automatically inside the DataMapper!
-                               $this->persistenceManager->getSession()->registerReconstitutedObject($object);
                        }
                        return $object;
                }
index ea25397..adf6079 100644 (file)
@@ -53,6 +53,22 @@ interface Tx_Extbase_Persistence_RepositoryInterface {
        public function remove($object);
 
        /**
+        * Returns all objects of this repository add()ed but not yet persisted to
+        * the storage layer.
+        *
+        * @return array An array of objects
+        */
+       public function getAddedObjects();
+
+       /**
+        * Returns an array with objects remove()d from the repository that
+        * had been persisted to the storage layer before.
+        *
+        * @return array
+        */
+       public function getRemovedObjects();
+
+       /**
         * Returns all objects of this repository.
         *
         * @return array An array of objects, empty if no objects found
index 1b6a1e8..b916476 100644 (file)
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
 
-require_once(PATH_t3lib . 'interfaces/interface.t3lib_singleton.php');
-
 /**
- * The persistence session - acts as a Unit of Work for EXCMVC's persistence framework.
+ * The persistence session - acts as a Unit of Work for Extbase persistence framework.
  *
  * @package Extbase
  * @subpackage Persistence
@@ -34,22 +32,6 @@ require_once(PATH_t3lib . 'interfaces/interface.t3lib_singleton.php');
 class Tx_Extbase_Persistence_Session implements t3lib_singleton {
 
        /**
-        * Objects added to the repository but not yet persisted in the persistence backend.
-        * The relevant objects are registered by the Tx_Extbase_Persistence_Repository.
-        *
-        * @var Tx_Extbase_Persistence_ObjectStorage
-        */
-       protected $addedObjects;
-
-       /**
-        * Objects removed but not yet persisted in the persistence backend.
-        * The relevant objects are registered by the Tx_Extbase_Persistence_Repository.
-        *
-        * @var Tx_Extbase_Persistence_ObjectStorage
-        */
-       protected $removedObjects;
-
-       /**
         * Objects which were reconstituted. The relevant objects are registered by
         * the Tx_Extbase_Persistence_Mapper_DataMapper.
         *
@@ -58,127 +40,20 @@ class Tx_Extbase_Persistence_Session implements t3lib_singleton {
        protected $reconstitutedObjects;
 
        /**
-        * This is an array of aggregate root class names. Aggegate root objects are an entry point to start committing
-        * changes. Aggregate root class names are registered by the Tx_Extbase_Persistence_Repository.
-        *
-        * @var array
-        */
-       protected $aggregateRootClassNames = array();
-
-       /**
         * Constructs a new Session
         *
         */
        public function __construct() {
-               $this->addedObjects = new Tx_Extbase_Persistence_ObjectStorage();
-               $this->removedObjects = new Tx_Extbase_Persistence_ObjectStorage();
                $this->reconstitutedObjects = new Tx_Extbase_Persistence_ObjectStorage();
        }
 
        /**
-        * Registers an added object.
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return void
-        */
-       public function registerAddedObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               if ($this->reconstitutedObjects->contains($object)) throw new InvalidArgumentException('The object was registered as reconstituted and can therefore not be registered as added.');
-               $this->removedObjects->detach($object);
-               $this->addedObjects->attach($object);
-       }
-
-       /**
-        * Unregisters an added object
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return void
-        */
-       public function unregisterAddedObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               $this->addedObjects->detach($object);
-       }
-
-       /**
-        * Returns all objects which have been registered as added objects
-        *
-        * @return array All added objects
-        */
-       public function getAddedObjects() {
-               return $this->addedObjects;
-       }
-
-       /**
-        * Returns TRUE if the given object is registered as added
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return bool TRUE if the given object is registered as added; otherwise FALSE
-        */
-       public function isAddedObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               return $this->addedObjects->contains($object);
-       }
-
-       /**
-        * Registers a removed object
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return void
-        */
-       public function registerRemovedObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               if ($this->addedObjects->contains($object)) {
-                       $this->addedObjects->detach($object);
-               } else {
-                       $this->removedObjects->attach($object);
-               }
-       }
-
-       /**
-        * Unregisters a removed object
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return void
-        */
-       public function unregisterRemovedObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               $this->removedObjects->detach($object);
-       }
-
-       /**
-        * Returns all objects which have been registered as removed objects
-        *
-        * @return array All removed objects
-        */
-       public function getRemovedObjects() {
-               return $this->removedObjects;
-       }
-
-       /**
-        * Returns TRUE if the given object is registered as removed
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return bool TRUE if the given object is registered as removed; otherwise FALSE
-        */
-       public function isRemovedObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               return $this->removedObjects->contains($object);
-       }
-
-       /**
-        * Registers all given objects as reconstituted
-        *
-        * @param array $objects
-        * @return void
-        */
-       public function registerReconstitutedObjects(array $objects) {
-               foreach ($objects as $object) {
-                       $this->registerReconstitutedObject($object);
-               }
-       }
-
-       /**
         * Registers a reconstituted object
         *
         * @param object $object
         * @return void
         */
        public function registerReconstitutedObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               if ($this->addedObjects->contains($object)) throw new InvalidArgumentException('The object was registered as added and can therefore not be registered as reconstituted.');
                $this->reconstitutedObjects->attach($object);
        }
 
@@ -202,83 +77,5 @@ class Tx_Extbase_Persistence_Session implements t3lib_singleton {
                return $this->reconstitutedObjects;
        }
 
-       /**
-        * Returns TRUE if the given object is registered as reconstituted
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return bool TRUE if the given object is registered as reconstituted; otherwise FALSE
-        */
-       public function isReconstitutedObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               return $this->reconstitutedObjects->contains($object);
-       }
-
-       /**
-        * Returns all objects marked as dirty (changed after reconstitution)
-        *
-        * @return array An array of dirty objects
-        */
-       public function getDirtyObjects() {
-               $dirtyObjects = new Tx_Extbase_Persistence_ObjectStorage();
-               foreach ($this->reconstitutedObjects as $object) {
-                       if ($object->_isDirty()) {
-                               $dirtyObjects->attach($object);
-                       }
-               }
-               return $dirtyObjects;
-       }
-
-       /**
-        * Returns TRUE if the given object is dirty
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return bool TRUE if the given object is dirty; otherwise FALSE
-        */
-       public function isDirtyObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               return $object->_isDirty();
-       }
-
-       /**
-        * Unregisters an object from all states
-        *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
-        * @return void
-        */
-       public function unregisterObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
-               $this->unregisterAddedObject($object);
-               $this->unregisterRemovedObject($object);
-               $this->unregisterReconstitutedObject($object);
-       }
-
-       /**
-        * Clears all ObjectStorages
-        *
-        * @return void
-        */
-       public function clear() {
-               $this->addedObjects = new Tx_Extbase_Persistence_ObjectStorage();
-               $this->removedObjects = new Tx_Extbase_Persistence_ObjectStorage();
-               $this->reconstitutedObjects = new Tx_Extbase_Persistence_ObjectStorage();
-               $this->aggregateRootClassNames = array();
-       }
-
-       /**
-        * Registers an aggregate root
-        *
-        * @param string $className The class to be registered
-        * @return void
-        */
-       public function registerAggregateRootClassName($className) {
-               $this->aggregateRootClassNames[] = $className;
-       }
-
-       /**
-        * Returns all aggregate root classes
-        *
-        * @return array An array holding the registered aggregate root classes
-        */
-       public function getAggregateRootClassNames() {
-               return $this->aggregateRootClassNames;
-       }
-
 }
 ?>
\ No newline at end of file
index 4fffd02..6036861 100644 (file)
@@ -592,7 +592,8 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                $rows = array();
                while ($row = $this->databaseHandle->sql_fetch_assoc($res)) {
                        if      ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
-                       $row = $this->doLanguageAndWorkspaceOverlay($source->getSelectorName(), $row);
+                               // FIXME The overlay is only performed if we query a single table; no joins
+                               $row = $this->doLanguageAndWorkspaceOverlay($source->getSelectorName(), $row);
                        }
                        if (is_array($row)) {
                                // TODO Check if this is necessary, maybe the last line is enough
@@ -635,7 +636,6 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                        } else {
                                require_once(PATH_t3lib . 'class.t3lib_page.php');
                                $this->pageSelectObject = t3lib_div::makeInstance( 't3lib_pageSelect' );
-                               //$this->pageSelectObject->versioningPreview =  TRUE;
                                if ($workspaceUid === NULL) {
                                        $workspaceUid = $GLOBALS['BE_USER']->workspace;
                                }
index a1f1949..6de52bb 100644 (file)
@@ -61,6 +61,16 @@ class Tx_Extbase_Property_Mapper {
         * @var Tx_Extbase_Validation_ValidatorResolver
         */
        protected $validatorResolver;
+       
+       /**
+        * @var Tx_Extbase_Reflection_Service
+        */
+       protected $reflectionService;
+
+       /**
+        * @var Tx_Extbase_Persistence_ManagerInterface
+        */
+       protected $persistenceManager;
 
        /**
         * Constructs the Property Mapper.
@@ -69,9 +79,20 @@ class Tx_Extbase_Property_Mapper {
                $objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_Manager');
                $this->validatorResolver = t3lib_div::makeInstance('Tx_Extbase_Validation_ValidatorResolver');
                $this->validatorResolver->injectObjectManager($objectManager);
+               $this->persistenceManager = Tx_Extbase_Dispatcher::getPersistenceManager();
        }
 
        /**
+        * Injects the Reflection Service
+        *
+        * @param Tx_Extbase_Reflection_Service
+        * @return void
+        */
+       public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
+               $this->reflectionService = $reflectionService;
+       }
+       
+       /**
         * Maps the given properties to the target object and validates the properties according to the defined
         * validators. If the result object is not valid, the operation will be undone (the target object remains
         * unchanged) and this method returns FALSE.
@@ -87,6 +108,7 @@ class Tx_Extbase_Property_Mapper {
         * @return boolean TRUE if the mapped properties are valid, otherwise FALSE
         * @see getMappingResults()
         * @see map()
+        * @api
         */
        public function mapAndValidate(array $propertyNames, $source, $target, $optionalPropertyNames = array(), Tx_Extbase_Validation_Validator_ObjectValidatorInterface $targetObjectValidator) {
                $backupProperties = array();
@@ -134,12 +156,19 @@ class Tx_Extbase_Property_Mapper {
         * @param array $optionalPropertyNames Names of optional properties. If a property is specified here and it doesn't exist in the source, no error is issued.
         * @return boolean TRUE if the properties could be mapped, otherwise FALSE
         * @see mapAndValidate()
+        * @api
         */
        public function map(array $propertyNames, $source, $target, $optionalPropertyNames = array()) {
-               if (!is_object($source) && !is_array($source) && ($source instanceof ArrayAccess)) throw new Tx_Extbase_Property_Exception_InvalidSource('The source object must be a valid object or array, ' . gettype($target) . ' given.', 1187807099);
+               if (!is_object($source) && !is_array($source)) throw new Tx_Extbase_Property_Exception_InvalidSource('The source object must be a valid object or array, ' . gettype($target) . ' given.', 1187807099);
                if (!is_object($target) && !is_array($target)) throw new Tx_Extbase_Property_Exception_InvalidTarget('The target object must be a valid object or array, ' . gettype($target) . ' given.', 1187807099);
 
-               $this->mappingResults = t3lib_div::makeInstance('Tx_Extbase_Property_MappingResults');
+               if (is_object($target)) {
+                       $targetClassSchema = $this->reflectionService->getClassSchema(get_class($target));
+               } else {
+                       $targetClassSchema = NULL;
+               }
+               
+               $this->mappingResults = new Tx_Extbase_Property_MappingResults();
                $propertyValues = array();
 
                foreach ($propertyNames as $propertyName) {
@@ -151,16 +180,44 @@ class Tx_Extbase_Property_Mapper {
                }
                foreach ($propertyNames as $propertyName) {
                        if (isset($propertyValues[$propertyName])) {
+
+                                       // source is array with (seemingly) uid strings and we have a target knowing the property
+                               if (is_array($propertyValues[$propertyName])
+                                               && is_string(current($propertyValues[$propertyName]))
+                                               && $targetClassSchema !== NULL
+                                               && $targetClassSchema->hasProperty($propertyName)) {
+
+                                       $propertyMetaData = $targetClassSchema->getProperty($propertyName);
+                                               // the target is array-like and the elementType is a class
+                                       if (in_array($propertyMetaData['type'], array('array', 'ArrayObject', 'SplObjectStorage')) && strpos($propertyMetaData['elementType'], '_') !== FALSE) {
+                                               foreach ($propertyValues[$propertyName] as $key => $value) {
+                                                               // convert to object and override original value
+                                                       $existingObject = $this->persistenceManager->getBackend()->getObjectByIdentifier($value, get_class($target));
+                                                       if ($existingObject === FALSE) throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('Querying the repository for the specified object was not successful.', 1249379517);
+                                                       $propertyValues[$propertyName][$key] = $existingObject;
+                                               }
+                                       }
+                                               // make sure we hand out what is expected
+                                       if ($propertyMetaData['type'] === 'ArrayObject') {
+                                               $propertyValues[$propertyName] = new ArrayObject($propertyValues[$propertyName]);
+                                       } elseif ($propertyMetaData['type']=== 'SplObjectStorage') {
+                                               $objects = $propertyValues[$propertyName];
+                                               $propertyValues[$propertyName] = new Tx_Extbase_Persistence_ObjectStorage();
+                                               foreach ($objects as $object) {
+                                                       $propertyValues[$propertyName]->attach($object);
+                                               }
+                                       }
+                               }
+
                                if (is_array($target)) {
                                        $target[$propertyName] = $source[$propertyName];
                                } elseif (Tx_Extbase_Reflection_ObjectAccess::setProperty($target, $propertyName, $propertyValues[$propertyName]) === FALSE) {
-                                       $this->mappingResults->addError(t3lib_div::makeInstance('Tx_Extbase_Error_Error', "Property '$propertyName' could not be set." , 1236783102), $propertyName);
+                                       $this->mappingResults->addError(new Tx_Extbase_Error_Error("Property '$propertyName' could not be set." , 1236783102), $propertyName);
                                }
                        } elseif (!in_array($propertyName, $optionalPropertyNames)) {
-                               $this->mappingResults->addError(t3lib_div::makeInstance('Tx_Extbase_Error_Error', "Required property '$propertyName' does not exist." , 1236785359), $propertyName);
+                               $this->mappingResults->addError(new Tx_Extbase_Error_Error("Required property '$propertyName' does not exist." , 1236785359), $propertyName);
                        }
                }
-
                return (!$this->mappingResults->hasErrors() && !$this->mappingResults->hasWarnings());
        }
 
@@ -168,6 +225,7 @@ class Tx_Extbase_Property_Mapper {
         * Returns the results of the last mapping operation.
         *
         * @return Tx_Extbase_Property_MappingResults The mapping results (or NULL if no mapping has been carried out yet)
+        * @api
         */
        public function getMappingResults() {
                return $this->mappingResults;
diff --git a/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php b/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php
new file mode 100644 (file)
index 0000000..aefbb56
--- /dev/null
@@ -0,0 +1,272 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * A class schema
+ *
+ * @version $Id: ClassSchema.php 2984 2009-08-04 13:04:35Z k-fish $
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_Reflection_ClassSchema {
+
+       /**
+        * Available model types
+        */
+       const MODELTYPE_ENTITY = 1;
+       const MODELTYPE_VALUEOBJECT = 2;
+
+       /**
+        * Specifies the allowed property types.
+        */
+       const ALLOWED_TYPES_PATTERN = '/^(?P<type>integer|int|float|boolean|string|DateTime|Tx_[a-zA-Z0-9_]+|array|ArrayObject|Tx_Extbase_Persistence_ObjectStorage)(?:<(?P<elementType>[a-zA-Z0-9_]+)>)?/';
+
+       /**
+        * Name of the class this schema is referring to
+        *
+        * @var string
+        */
+       protected $className;
+
+       /**
+        * Model type of the class this schema is referring to
+        *
+        * @var integer
+        */
+       protected $modelType = self::MODELTYPE_ENTITY;
+
+       /**
+        * Whether a repository exists for the class this schema is referring to
+        * @var boolean
+        */
+       protected $aggregateRoot = FALSE;
+
+       /**
+        * The name of the property holding the uuid of an entity, if any.
+        *
+        * @var string
+        */
+       protected $uuidPropertyName;
+
+       /**
+        * Properties of the class which need to be persisted
+        *
+        * @var array
+        */
+       protected $properties = array();
+
+       /**
+        * The properties forming the identity of an object
+        *
+        * @var array
+        */
+       protected $identityProperties = array();
+
+       /**
+        * Constructs this class schema
+        *
+        * @param string $className Name of the class this schema is referring to
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function __construct($className) {
+               $this->className = $className;
+       }
+
+       /**
+        * Returns the class name this schema is referring to
+        *
+        * @return string The class name
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getClassName() {
+               return $this->className;
+       }
+
+       /**
+        * Adds (defines) a specific property and its type.
+        *
+        * @param string $name Name of the property
+        * @param string $type Type of the property (see ALLOWED_TYPES_PATTERN)
+        * @param boolean $lazy Whether the property should be lazy-loaded when reconstituting
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function addProperty($name, $type, $lazy = FALSE) {
+               $matches = array();
+               if (preg_match(self::ALLOWED_TYPES_PATTERN, $type, $matches)) {
+                       $type = ($matches['type'] === 'int') ? 'integer' : $matches['type'];
+                       $elementType = isset($matches['elementType']) ? $matches['elementType'] : NULL;
+
+                       if ($elementType !== NULL && !in_array($type, array('array', 'ArrayObject', 'SplObjectStorage'))) {
+                               throw new Tx_Extbase_Reflection_Exception_InvalidPropertyType('Property  of type "' . $type . '" must not have an element type hint (' . $elementType . ').', 1248103053);
+                       }
+
+                       $this->properties[$name] = array(
+                               'type' => $type,
+                               'elementType' => $elementType,
+                               'lazy' => $lazy
+                       );
+               } else {
+                       throw new Tx_Extbase_Reflection_Exception_InvalidPropertyType('Invalid property type encountered: ' . $type, 1220387528);
+               }
+       }
+
+       /**
+        * Returns the given property defined in this schema. Check with
+        * hasProperty($propertyName) before!
+        *
+        * @return array
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function getProperty($propertyName) {
+               return $this->properties[$propertyName];
+       }
+
+       /**
+        * Returns all properties defined in this schema
+        *
+        * @return array
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getProperties() {
+               return $this->properties;
+       }
+
+       /**
+        * Sets the model type of the class this schema is referring to.
+        *
+        * @param integer The model type, one of the MODELTYPE_* constants.
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function setModelType($modelType) {
+               if ($modelType < self::MODELTYPE_ENTITY || $modelType > self::MODELTYPE_VALUEOBJECT) throw new InvalidArgumentException('"' . $modelType . '" is an invalid model type.', 1212519195);
+               $this->modelType = $modelType;
+       }
+
+       /**
+        * Returns the model type of the class this schema is referring to.
+        *
+        * @return integer The model type, one of the MODELTYPE_* constants.
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getModelType() {
+               return $this->modelType;
+       }
+
+       /**
+        * Marks the class if it is root of an aggregate and therefore accessible
+        * through a repository - or not.
+        *
+        * @param boolean $isRoot TRUE if it is the root of an aggregate
+        * @return void
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function setAggregateRoot($isRoot) {
+               $this->aggregateRoot = $isRoot;
+       }
+
+       /**
+        * Whether the class is an aggregate root and therefore accessible through
+        * a repository.
+        *
+        * @return boolean TRUE if it is managed
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function isAggregateRoot() {
+               return $this->aggregateRoot;
+       }
+
+       /**
+        * If the class schema has a certain property.
+        *
+        * @param string $propertyName Name of the property
+        * @return boolean
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function hasProperty($propertyName) {
+               return array_key_exists($propertyName, $this->properties);
+       }
+
+       /**
+        * Sets the property marked as uuid of an object with @uuid
+        *
+        * @param string $propertyName
+        * @return void
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function setUUIDPropertyName($propertyName) {
+               if (!array_key_exists($propertyName, $this->properties)) {
+                       throw new InvalidArgumentException('Property "' . $propertyName . '" must be added to the class schema before it can be marked as UUID property.', 1233863842);
+               }
+
+               $this->uuidPropertyName = $propertyName;
+       }
+
+       /**
+        * Gets the name of the property marked as uuid of an object
+        *
+        * @return string
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function getUUIDPropertyName() {
+               return $this->uuidPropertyName;
+       }
+
+       /**
+        * Marks the given property as one of properties forming the identity
+        * of an object. The property must already be registered in the class
+        * schema.
+        *
+        * @param string $propertyName
+        * @return void
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function markAsIdentityProperty($propertyName) {
+               if (!array_key_exists($propertyName, $this->properties)) {
+                       throw new InvalidArgumentException('Property "' . $propertyName . '" must be added to the class schema before it can be marked as identity property.', 1233775407);
+               }
+               if ($this->properties[$propertyName]['lazy'] === TRUE) {
+                       throw new InvalidArgumentException('Property "' . $propertyName . '" must not be makred for lazy loading to be marked as identity property.', 1239896904);
+               }
+
+               $this->identityProperties[$propertyName] = $this->properties[$propertyName]['type'];
+       }
+
+       /**
+        * Gets the properties (names and types) forming the identity of an object.
+        *
+        * @return array
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        * @see markAsIdentityProperty()
+        */
+       public function getIdentityProperties() {
+               return $this->identityProperties;
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/Reflection/Exception/InvalidPropertyType.php b/typo3/sysext/extbase/Classes/Reflection/Exception/InvalidPropertyType.php
new file mode 100644 (file)
index 0000000..c19fc02
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * An "Invalid Property Type" exception
+ *
+ * @version $Id: InvalidPropertyType.php 2835 2009-07-20 11:36:13Z k-fish $
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_Reflection_Exception_InvalidPropertyType extends Tx_Extbase_Reflection_Exception {
+}
+
+?>
\ No newline at end of file
index 75c017a..9549cfa 100644 (file)
@@ -115,7 +115,9 @@ class Tx_Extbase_Reflection_ObjectAccess {
 
                foreach (get_class_methods($object) as $methodName) {
                        if (substr($methodName, 0, 3) === 'get') {
-                               $declaredPropertyNames[] = t3lib_div::lcfirst(substr($methodName, 3));
+                               $propertyName = substr($methodName, 3);
+                               $propertyName[0] = strtolower($propertyName[0]);
+                               $declaredPropertyNames[] = $propertyName;
                        }
                }
 
index 5f46231..579556f 100644 (file)
@@ -144,8 +144,10 @@ class Tx_Extbase_Reflection_Service implements t3lib_Singleton {
                if ($this->initialized) throw new Tx_Extbase_Reflection_Exception('The Reflection Service can only be initialized once.', 1232044696);
 
                $this->loadFromCache();
-
+               
                $this->initialized = TRUE;
+       
+               $this->buildClassSchemata();
        }
 
        /**
@@ -169,6 +171,20 @@ class Tx_Extbase_Reflection_Service implements t3lib_Singleton {
        }
 
        /**
+        * Searches for and returns all names of classes which are tagged by the specified tag.
+        * If no classes were found, an empty array is returned.
+        *
+        * @param string $tag Tag to search for
+        * @return array An array of class names tagged by the tag
+        * @author Robert Lemke <robert@typo3.org>
+        * @api
+        */
+       public function getClassNamesByTag($tag) {
+               if ($this->initialized !== TRUE) throw new Tx_Extbase_Reflection_Exception('Reflection has not yet been initialized.', 1238667825);
+               return (isset($this->taggedClasses[$tag])) ? $this->taggedClasses[$tag] : array();
+       }
+       
+       /**
         * Returns the names of all properties of the specified class
         *
         * @param string $className Name of the class to return the property names of
@@ -180,6 +196,18 @@ class Tx_Extbase_Reflection_Service implements t3lib_Singleton {
        }
 
        /**
+        * Returns the class schema for the given class
+        *
+        * @param mixed $classNameOrObject The class name or an object
+        * @return Tx_Extbase_Reflection_ClassSchema
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function getClassSchema($classNameOrObject) {
+               $className = is_object($classNameOrObject) ? get_class($classNameOrObject) : $classNameOrObject;
+               return isset($this->classSchemata[$className]) ? $this->classSchemata[$className] : NULL;
+       }
+
+       /**
         * Returns all tags and their values the specified method is tagged with
         *
         * @param string $className Name of the class containing the method
@@ -231,6 +259,69 @@ class Tx_Extbase_Reflection_Service implements t3lib_Singleton {
                if (!isset($this->propertyTagsValues[$className])) return array();
                return (isset($this->propertyTagsValues[$className][$propertyName])) ? $this->propertyTagsValues[$className][$propertyName] : array();
        }
+       
+       /**
+        * Returns the values of the specified class property tag
+        *
+        * @param string $className Name of the class containing the property
+        * @param string $propertyName Name of the tagged property
+        * @param string $tag Tag to return the values of
+               if (!isset($this->propertyTagsValues[$className])) return array();
+        * @return array An array of values or an empty array if the tag was not found
+        * @author Robert Lemke <robert@typo3.org>
+        * @api
+        */
+       public function getPropertyTagValues($className, $propertyName, $tag) {
+               if (!isset($this->reflectedClassNames[$className])) $this->reflectClass($className);
+               if (!isset($this->propertyTagsValues[$className][$propertyName])) return array();
+               return (isset($this->propertyTagsValues[$className][$propertyName][$tag])) ? $this->propertyTagsValues[$className][$propertyName][$tag] : array();
+       }
+       
+       /**
+        * Tells if the specified class is known to this reflection service and
+        * reflection information is available.
+        *
+        * @param string $className Name of the class
+        * @return boolean If the class is reflected by this service
+        * @author Robert Lemke <robert@typo3.org>
+        * @api
+        */
+       public function isClassReflected($className) {
+               return isset($this->reflectedClassNames[$className]);
+       }
+       
+       /**
+        * Tells if the specified class is tagged with the given tag
+        *
+        * @param string $className Name of the class
+        * @param string $tag Tag to check for
+        * @return boolean TRUE if the class is tagged with $tag, otherwise FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        * @api
+        */
+       public function isClassTaggedWith($className, $tag) {
+               if ($this->initialized === FALSE) return FALSE;
+               if (!isset($this->reflectedClassNames[$className])) $this->reflectClass($className);
+               if (!isset($this->classTagsValues[$className])) return FALSE;
+               return isset($this->classTagsValues[$className][$tag]);
+       }
+
+       /**
+        * Tells if the specified class property is tagged with the given tag
+        *
+        * @param string $className Name of the class
+        * @param string $propertyName Name of the property
+        * @param string $tag Tag to check for
+        * @return boolean TRUE if the class property is tagged with $tag, otherwise FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        * @api
+        */
+       public function isPropertyTaggedWith($className, $propertyName, $tag) {
+               if (!isset($this->reflectedClassNames[$className])) $this->reflectClass($className);
+               if (!isset($this->propertyTagsValues[$className])) return FALSE;
+               if (!isset($this->propertyTagsValues[$className][$propertyName])) return FALSE;
+               return isset($this->propertyTagsValues[$className][$propertyName][$tag]);
+       }
 
        /**
         * Reflects the given class and stores the results in this service's properties.
@@ -276,6 +367,45 @@ class Tx_Extbase_Reflection_Service implements t3lib_Singleton {
 
                $this->cacheNeedsUpdate = TRUE;
        }
+       
+       /**
+        * Builds class schemata from classes annotated as entities or value objects
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       protected function buildClassSchemata() {
+               $this->classSchemata = array();
+
+               $classNames = array_merge($this->getClassNamesByTag('entity'), $this->getClassNamesByTag('valueobject'));
+               foreach ($classNames as $className) {
+                       $classSchema = new Tx_Extbase_Reflection_ClassSchema($className);
+                       if ($this->isClassTaggedWith($className, 'entity')) {
+                               $classSchema->setModelType(Tx_Extbase_Reflection_ClassSchema::MODELTYPE_ENTITY);
+
+                               $possibleRepositoryClassName = str_replace('_Model_', '_Repository_', $className) . 'Repository';
+                               if ($this->isClassReflected($possibleRepositoryClassName)) {
+                                       $classSchema->setAggregateRoot(TRUE);
+                               }
+                       } elseif ($this->isClassTaggedWith($className, 'valueobject')) {
+                               $classSchema->setModelType(Tx_Extbase_Reflection_ClassSchema::MODELTYPE_VALUEOBJECT);
+                       }
+
+                       foreach ($this->getClassPropertyNames($className) as $propertyName) {
+                               if (!$this->isPropertyTaggedWith($className, $propertyName, 'transient') && $this->isPropertyTaggedWith($className, $propertyName, 'var')) {
+                                       $classSchema->addProperty($propertyName, implode(' ', $this->getPropertyTagValues($className, $propertyName, 'var')), $this->isPropertyTaggedWith($className, $propertyName, 'lazy'));
+                               }
+                               if ($this->isPropertyTaggedWith($className, $propertyName, 'uuid')) {
+                                       $classSchema->setUUIDPropertyName($propertyName);
+                               }
+                               if ($this->isPropertyTaggedWith($className, $propertyName, 'identity')) {
+                                       $classSchema->markAsIdentityProperty($propertyName);
+                               }
+                       }
+                       $this->classSchemata[$className] = $classSchema;
+               }
+       }
 
        /**
         * Converts the given parameter reflection into an information array
index 911f5f3..15891a9 100644 (file)
  * @package Extbase
  * @subpackage Utility
  * @version $ID:$
- * @author Dmitry Dulepov <dmitry@typo3.org>
- * @author Sebastian Kurf\9frst <sebastian@typo3.org>
- * @author Jochen Rau <jochen.rau@typoplanet.de>
  */
 class Tx_Extbase_Utility_Extension {
 
        /**
+        * Add auto-generated TypoScript to configure the Extbase Dispatcher.
+        *
+        * When adding a frontend plugin you will have to add both an entry to the TCA definition
+        * of tt_content table AND to the TypoScript template which must initiate the rendering.
+        * Since the static template with uid 43 is the "content.default" and practically always
+        * used for rendering the content elements it's very useful to have this function automatically
+        * adding the necessary TypoScript for calling the appropriate controller and action of your plugin.
+        * It will also work for the extension "css_styled_content"
+        * FOR USE IN ext_localconf.php FILES
+        * Usage: 2
+        *
+        * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
+        * @param string $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
+        * @param string $controllerActions is an array of allowed combinations of controller and action stored in an array (controller name as key and a comma separated list of action names as value, the first controller and its first action is chosen as default)
+        * @param string $nonCachableControllerActions is an optional array of controller name and  action names which should not be cached (array as defined in $controllerActions)
+        * @param string $defaultControllerAction is an optional array controller name (as array key) and action name (as array value) that should be called as default
+        * @return void
+        */
+       public static function configureDispatcher($extensionName, $pluginName, array $controllerActions, array $nonCachableControllerActions = array()) {
+               if (empty($pluginName)) {
+                       throw new InvalidArgumentException('The plugin name must not be empty', 1239891987);
+               }
+               if (empty($extensionName)) {
+                       throw new InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
+               }
+               $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
+               $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
+
+               $controllerCounter = 1;
+               $hasMultipleActionsCounter = 0;
+               $controllers = '';
+               foreach ($controllerActions as $controller => $actionsList) {
+                       $controllers .= '
+               ' . $controllerCounter . '.controller = ' . $controller . '
+               ' . $controllerCounter . '.actions = ' . $actionsList;
+                       $controllerCounter++;
+                       if (strpos($actionsList, ',') !== FALSE) {
+                               $hasMultipleActionsCounter++;
+                       }
+               }
+
+               $switchableControllerActions = '';
+               if ($controllerCounter > 1 || $hasMultipleActionsCounter > 0) {
+                               $switchableControllerActions = '
+       switchableControllerActions {' . $controllers . '
+       }';
+               }
+
+               reset($controllerActions);
+               $defaultController = key($controllerActions);
+               $controller = '
+       controller = ' . $defaultController;
+               $defaultAction = array_shift(t3lib_div::trimExplode(',', current($controllerActions)));
+               $action = '
+       action = ' . $defaultAction;
+
+               $nonCachableActions = array();
+               if (!empty($nonCachableControllerActions[$defaultController])) {
+                       $nonCachableActions = t3lib_div::trimExplode(',', $nonCachableControllerActions[$defaultController]);
+               }
+               $cachableActions = array_diff(t3lib_div::trimExplode(',', $controllerActions[$defaultController]), $nonCachableActions);
+
+               $contentObjectType = in_array($defaultAction, $nonCachableActions) ? 'USER_INT' : 'USER';
+
+               $conditions = '';
+               foreach ($controllerActions as $controllerName => $actionsList) {
+                       if (!empty($nonCachableControllerActions[$controllerName])) {
+                               $nonCachableActions = t3lib_div::trimExplode(',', $nonCachableControllerActions[$controllerName]);
+                               $cachableActions = array_diff(t3lib_div::trimExplode(',', $controllerActions[$controllerName]), $nonCachableActions);
+                               if (($contentObjectType == 'USER' && count($nonCachableActions) > 0)
+                                       || ($contentObjectType == 'USER_INT' && count($cachableActions) > 0)) {
+
+                                       $conditions .= '
+[globalString = GP:tx_' . $pluginSignature . '|controller = ' . $controllerName . '] && [globalString = GP:tx_' . $pluginSignature . '|action = /' . implode('|', $contentObjectType === 'USER' ? $nonCachableActions : $cachableActions) . '/]
+tt_content.list.20.' . $pluginSignature . ' = ' . ($contentObjectType === 'USER' ? 'USER_INT' : 'USER') . '
+[global]
+';
+                               }
+                       }
+               }
+
+               $pluginTemplate = trim('plugin.tx_' . strtolower($extensionName) . '.settings {
+}
+plugin.tx_' . strtolower($extensionName) . '.persistence {
+       enableAutomaticCacheClearing = 1
+       # storagePid
+       classes {
+       }
+}');
+               t3lib_extMgm::addTypoScript($extensionName, 'setup', '
+# Setting ' . $extensionName . ' plugin TypoScript
+' . $pluginTemplate);
+
+               $pluginContent = trim('
+tt_content.list.20.' . $pluginSignature . ' = ' . $contentObjectType . '
+tt_content.list.20.' . $pluginSignature . ' {
+       userFunc = tx_extbase_dispatcher->dispatch
+       pluginName = ' . $pluginName . '
+       extensionName = ' . $extensionName . '
+       ' . $controller .
+       $action .
+       $switchableControllerActions . '
+
+       persistence =< plugin.tx_' . strtolower($extensionName) . '.persistence
+}
+' . $conditions);
+
+               t3lib_extMgm::addTypoScript($extensionName, 'setup', '
+# Setting ' . $extensionName . ' plugin TypoScript
+' . $pluginContent, 43);
+       }
+
+       /**
+        * Register an Extbase PlugIn into backend's list of plugins
+        * FOR USE IN ext_tables.php FILES
+        *
+        * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
+        * @param string $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
+        * @param string $pluginTitle is a speaking title of the plugin that will be displayed in the drop down menu in the backend
+        * @return void
+        */
+       public static function registerPlugin($extensionName, $pluginName, $pluginTitle) {
+               if (empty($pluginName)) {
+                       throw new InvalidArgumentException('The plugin name must not be empty', 1239891987);
+               }
+               if (empty($extensionName)) {
+                       throw new InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
+               }
+               $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
+               $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
+
+               t3lib_extMgm::addPlugin(array($pluginTitle, $pluginSignature), 'list_type');
+       }
+       
+       /**
+        * Registers an Extbase module (main or sub) to the backend interface.
+        * FOR USE IN ext_tables.php FILES
+        *
+        * @param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
+        * @param array $controllerActions is an array of allowed combinations of controller and action stored in an array (controller name as key and a comma separated list of action names as value, the first controller and its first action is chosen as default)
+        * @param array $config The configuration options of the module (icon, locallang.xml file)
+        * @param string $main The main module key, $sub is the submodule key. So $main would be an index in the $TBE_MODULES array and $sub could be an element in the lists there. If $main is not set a blank $extensionName module is created
+        * @param string $sub The submodule key. If $sub is not set a blank $main module is created
+        * @param string $position This can be used to set the position of the $sub module within the list of existing submodules for the main module. $position has this syntax: [cmd]:[submodule-key]. cmd can be "after", "before" or "top" (or blank which is default). If "after"/"before" then submodule will be inserted after/before the existing submodule with [submodule-key] if found. If not found, the bottom of list. If "top" the module is inserted in the top of the submodule list.
+        * @return void
+        */
+       public static function registerModule($extensionName, array $controllerActions, $config = array(), $main = '', $sub = '', $position = '') {
+               if (empty($extensionName)) {
+                       throw new InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
+               }
+               $extensionKey = $extensionName;
+               $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
+               
+               $path = t3lib_extMgm::extPath($extensionKey, 'Classes/');
+               $relPath = t3lib_extMgm::extRelPath($extensionKey) . 'Classes/';
+               
+               if (!isset($GLOBALS['TBE_EXTBASE_MODULES'])) {
+                       $GLOBALS['TBE_EXTBASE_MODULES'] = array();
+               }
+               
+               // TODO Make if condition explicit
+               if ($main && !isset($GLOBALS['TBE_MODULES'][$main])) {
+                       $main = $extensionName . ucfirst($main);
+               } else {
+                       $main = $main ? $main : $extensionName;
+               }
+               
+               if (!is_array($config) || count($config) == 0) {
+                       $config['access'] = 'admin';
+                       $config['icon'] = '';
+                       $config['labels'] = '';
+                       $config['extRelPath'] = $relPath;
+               }
+               
+               $key = $main . ($sub ? '_' . $sub : '');
+               
+               $moduleConfig = array(
+                       'name' => $key,
+                       'extensionKey' => $extensionKey,
+                       'extensionName' => $extensionName,
+                       'controllerActions' => $controllerActions,
+                       'config' => $config,
+               );
+               $GLOBALS['TBE_EXTBASE_MODULES'][$key] = $moduleConfig;
+               $GLOBALS['TBE_EXTBASE_MODULES'][$key]['configureModuleFunction'] = array('Tx_Extbase_Utility_Module', 'setModuleConfiguration');
+               
+               t3lib_extMgm::addModule($main, $sub, $position, $path);
+       }
+       
+       /**
+        * This method is called from t3lib_loadModules::checkMod and it replaces old conf.php.
+        * 
+        * @param string $key The module name
+        * @param string $fullpath      Absolute path to module
+        * @param array $MCONF Reference to the array holding the configuration of the module
+        * @param array $MLANG Reference to the array holding the localized module labels
+        * @return array Configuration of the module
+        */
+       public function setModuleConfiguration($key, $fullpath, &$MCONF, &$MLANG) {
+               $path = preg_replace('/\/[^\/.]+\/\.\.\//', '/', $fullpath); // because 'path/../path' does not work
+               $config = $GLOBALS['TBE_EXTBASE_MODULES'][$key]['config'];
+               define('TYPO3_MOD_PATH', $config['extRelPath']);
+
+               $GLOBALS['BACK_PATH'] = '';
+
+                       // Fill $MCONF
+               $MCONF['name'] = $key;
+               $MCONF['access'] = $config['access'];
+               $MCONF['script'] = '_DISPATCH';
+
+               if (substr($config['icon'], 0, 4) === 'EXT:') {
+                       list($extKey, $local) = explode('/', substr($config['icon'], 4), 2);
+                       $config['icon'] = t3lib_extMgm::extRelPath($extKey) . $local;
+               }
+         
+                       // Initialize search for alternative icon:
+               $altIconKey = 'MOD:' . $key . '/' . $config['icon'];            // Alternative icon key (might have an alternative set in $TBE_STYLES['skinImg']
+               $altIconAbsPath = is_array($GLOBALS['TBE_STYLES']['skinImg'][$altIconKey]) ? t3lib_div::resolveBackPath(PATH_typo3.$GLOBALS['TBE_STYLES']['skinImg'][$altIconKey][0]) : '';
+
+                       // Set icon, either default or alternative:
+               if ($altIconAbsPath && @is_file($altIconAbsPath)) {
+                       $tabImage = $altIconAbsPath;
+               } else {
+                               // Setting default icon:
+                       $tabImage = $config['icon'];
+               }
+
+                       // Fill $MLANG
+               $MLANG['default']['ll_ref'] = $config['labels'];   
+               
+                       // Finally, set the icon with correct path:
+               if (substr($tabImage, 0 ,3) === '../') {
+                       $MLANG['default']['tabs_images']['tab'] = PATH_site . substr($tabImage, 3);
+               } else {
+                       $MLANG['default']['tabs_images']['tab'] = PATH_typo3 . $tabImage;
+               }
+               
+                       // If LOCAL_LANG references are used for labels of the module:
+               if ($MLANG['default']['ll_ref']) {
+                               // Now the 'default' key is loaded with the CURRENT language - not the english translation...
+                       $MLANG['default']['labels']['tablabel'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tablabel');
+                       $MLANG['default']['labels']['tabdescr'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_labels_tabdescr');
+                       $MLANG['default']['tabs']['tab'] = $GLOBALS['LANG']->sL($MLANG['default']['ll_ref'] . ':mlang_tabs_tab');
+                       $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $key . '_');
+               } else {        // ... otherwise use the old way:
+                       $GLOBALS['LANG']->addModuleLabels($MLANG['default'], $key . '_');
+                       $GLOBALS['LANG']->addModuleLabels($MLANG[$GLOBALS['LANG']->lang], $key . '_');
+               }
+               
+                       // Fill $modconf
+               $modconf['script'] = 'mod.php?M=TX_' . rawurlencode($key);
+               $modconf['name'] = $key;
+                                       
+                               // Default tab setting
+               if ($MCONF['defaultMod']) {
+                       $modconf['defaultMod'] = $MCONF['defaultMod'];
+               }
+                       // Navigation Frame Script (GET params could be added)
+               if ($MCONF['navFrameScript']) {
+                       $navFrameScript = explode('?', $MCONF['navFrameScript']);
+                       $navFrameScript = $navFrameScript[0];
+                       if (file_exists($path . '/' . $navFrameScript)) {
+                               $modconf['navFrameScript'] = $this->getRelativePath(PATH_typo3, $fullpath . '/' . $MCONF['navFrameScript']);
+                       }
+               }
+               
+                       // Additional params for Navigation Frame Script: "&anyParam=value&moreParam=1"
+               if ($MCONF['navFrameScriptParam']) {
+                       $modconf['navFrameScriptParam'] = $MCONF['navFrameScriptParam'];
+               }
+                               
+               return $modconf;
+       }
+
+       // TODO PHPdoc
+       public static function convertCamelCaseToLowerCaseUnderscored($string) {
+               static $conversionMap = array();
+               if (!isset($conversionMap[$string])) {
+                       $conversionMap[$string] = strtolower(preg_replace('/(?<=\w)([A-Z])/', '_\\1', $string));
+               }
+               return $conversionMap[$string];
+       }
+
+       public static function convertUnderscoredToLowerCamelCase($string) {
+               $string = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($string))));
+               $string[0] = strtolower($string[0]);
+               return $string;
+       }
+
+       public static function convertLowerUnderscoreToUpperCamelCase($camelCasedString) {
+               return t3lib_div::underscoredToUpperCamelCase($camelCasedString);
+       }
+       
+       /**
         * Build the autoload registry for a given extension and place it ext_autoload.php.
         *
         * @param       string  $extensionKey   Key of the extension
diff --git a/typo3/sysext/extbase/Classes/Utility/Plugin.php b/typo3/sysext/extbase/Classes/Utility/Plugin.php
deleted file mode 100644 (file)
index 14ac149..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-<?php
-/***************************************************************
-*  Copyright notice
-*
-*  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
-*  All rights reserved
-*
-*  This class is a backport of the corresponding class of FLOW3.
-*  All credits go to the v5 team.
-*
-*  This script is part of the TYPO3 project. The TYPO3 project is
-*  free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*
-*  The GNU General Public License can be found at
-*  http://www.gnu.org/copyleft/gpl.html.
-*
-*  This script is distributed in the hope that it will be useful,
-*  but WITHOUT ANY WARRANTY; without even the implied warranty of
-*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-*  GNU General Public License for more details.
-*
-*  This copyright notice MUST APPEAR in all copies of the script!
-***************************************************************/
-
-/**
- * Utilities to manage the plugins of an extension
- *
- * @package Extbase
- * @subpackage Utility
- * @version $ID:$
- */
-class Tx_Extbase_Utility_Plugin {
-
-       /**
-        * Add auto-generated TypoScript to configure the Extbase Dispatcher.
-        *
-        * When adding a frontend plugin you will have to add both an entry to the TCA definition
-        * of tt_content table AND to the TypoScript template which must initiate the rendering.
-        * Since the static template with uid 43 is the "content.default" and practically always
-        * used for rendering the content elements it's very useful to have this function automatically
-        * adding the necessary TypoScript for calling the appropriate controller and action of your plugin.
-        * It will also work for the extension "css_styled_content"
-        * FOR USE IN ext_localconf.php FILES
-        * Usage: 2
-        *
-        * @param       string          $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
-        * @param       string          $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
-        * @param       string          $controllerActions is an array of allowed combinations of controller and action stored in an array (controller name as key and a comma separated list of action names as value, the first controller and its first action is chosen as default)
-        * @param       string          $nonCachableControllerActions is an optional array of controller name and  action names which should not be cached (array as defined in $controllerActions)
-        * @param       string          $defaultControllerAction is an optional array controller name (as array key) and action name (as array value) that should be called as default
-        * @return      void
-        */
-       public static function configureDispatcher($extensionName, $pluginName, array $controllerActions, array $nonCachableControllerActions = array()) {
-               if (empty($pluginName)) {
-                       throw new InvalidArgumentException('The plugin name must not be empty', 1239891987);
-               }
-               if (empty($extensionName)) {
-                       throw new InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
-               }
-               $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
-               $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
-
-               $controllerCounter = 1;
-               $hasMultipleActionsCounter = 0;
-               $controllers = '';
-               foreach ($controllerActions as $controller => $actionsList) {
-                       $controllers .= '
-               ' . $controllerCounter . '.controller = ' . $controller . '
-               ' . $controllerCounter . '.actions = ' . $actionsList;
-                       $controllerCounter++;
-                       if (strpos($actionsList, ',') !== FALSE) {
-                               $hasMultipleActionsCounter++;
-                       }
-               }
-
-               $switchableControllerActions = '';
-               if ($controllerCounter > 1 || $hasMultipleActionsCounter > 0) {
-                               $switchableControllerActions = '
-       switchableControllerActions {' . $controllers . '
-       }';
-               }
-
-               reset($controllerActions);
-               $defaultController = key($controllerActions);
-               $controller = '
-       controller = ' . $defaultController;
-               $defaultAction = array_shift(t3lib_div::trimExplode(',', current($controllerActions)));
-               $action = '
-       action = ' . $defaultAction;
-
-               $nonCachableActions = array();
-               if (!empty($nonCachableControllerActions[$defaultController])) {
-                       $nonCachableActions = t3lib_div::trimExplode(',', $nonCachableControllerActions[$defaultController]);
-               }
-               $cachableActions = array_diff(t3lib_div::trimExplode(',', $controllerActions[$defaultController]), $nonCachableActions);
-
-               $contentObjectType = in_array($defaultAction, $nonCachableActions) ? 'USER_INT' : 'USER';
-
-               $conditions = '';
-               foreach ($controllerActions as $controllerName => $actionsList) {
-                       if (!empty($nonCachableControllerActions[$controllerName])) {
-                               $nonCachableActions = t3lib_div::trimExplode(',', $nonCachableControllerActions[$controllerName]);
-                               $cachableActions = array_diff(t3lib_div::trimExplode(',', $controllerActions[$controllerName]), $nonCachableActions);
-                               if (($contentObjectType == 'USER' && count($nonCachableActions) > 0)
-                                       || ($contentObjectType == 'USER_INT' && count($cachableActions) > 0)) {
-
-                                       $conditions .= '
-[globalString = GP:tx_' . $pluginSignature . '|controller = ' . $controllerName . '] && [globalString = GP:tx_' . $pluginSignature . '|action = /' . implode('|', $contentObjectType === 'USER' ? $nonCachableActions : $cachableActions) . '/]
-tt_content.list.20.' . $pluginSignature . ' = ' . ($contentObjectType === 'USER' ? 'USER_INT' : 'USER') . '
-[global]
-';
-                               }
-                       }
-               }
-
-               $pluginTemplate = trim('plugin.tx_' . strtolower($extensionName) . '.settings {
-}
-plugin.tx_' . strtolower($extensionName) . '.persistence {
-       enableAutomaticCacheClearing = 1
-       # storagePid
-       classes {
-       }
-}');
-               t3lib_extMgm::addTypoScript($extensionName, 'setup', '
-# Setting ' . $extensionName . ' plugin TypoScript
-' . $pluginTemplate);
-
-               $pluginContent = trim('
-tt_content.list.20.' . $pluginSignature . ' = ' . $contentObjectType . '
-tt_content.list.20.' . $pluginSignature . ' {
-       userFunc = tx_extbase_dispatcher->dispatch
-       pluginName = ' . $pluginName . '
-       extensionName = ' . $extensionName . '
-       ' . $controller .
-       $action .
-       $switchableControllerActions . '
-
-       persistence =< plugin.tx_' . strtolower($extensionName) . '.persistence
-}
-' . $conditions);
-
-               t3lib_extMgm::addTypoScript($extensionName, 'setup', '
-# Setting ' . $extensionName . ' plugin TypoScript
-' . $pluginContent, 43);
-       }
-
-       /**
-        * Register an Extbase PlugIn into backend's list of plugins
-        * FOR USE IN ext_tables.php FILES
-        *
-        * @param       string          $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
-        * @param       string          $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
-        * @param       string          $pluginTitle is a speaking title of the plugin that will be displayed in the drop down menu in the backend
-        * @return      void
-        */
-       public static function registerPlugin($extensionName, $pluginName, $pluginTitle) {
-               if (empty($pluginName)) {
-                       throw new InvalidArgumentException('The plugin name must not be empty', 1239891987);
-               }
-               if (empty($extensionName)) {
-                       throw new InvalidArgumentException('The extension name was invalid (must not be empty and must match /[A-Za-z][_A-Za-z0-9]/)', 1239891989);
-               }
-               $extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
-               $pluginSignature = strtolower($extensionName) . '_' . strtolower($pluginName);
-
-               t3lib_extMgm::addPlugin(array($pluginTitle, $pluginSignature), 'list_type');
-       }
-
-       // TODO Remove the next 3 functions; only for compatibility resons
-
-       public static function convertCamelCaseToLowerCaseUnderscored($string) {
-               static $conversionMap = array();
-               if (!isset($conversionMap[$string])) {
-                       $conversionMap[$string] = strtolower(preg_replace('/(?<=\w)([A-Z])/', '_\\1', $string));
-               }
-               return $conversionMap[$string];
-       }
-
-       public static function convertUnderscoredToLowerCamelCase($string) {
-               $string = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($string))));
-               $string[0] = strtolower($string[0]);
-               return $string;
-       }
-
-       public static function convertLowerUnderscoreToUpperCamelCase($camelCasedString) {
-               return t3lib_div::underscoredToUpperCamelCase($camelCasedString);
-       }
-
-}
-?>
\ No newline at end of file
index 8532017..1d7228b 100644 (file)
@@ -5,7 +5,7 @@
 *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
 *  All rights reserved
 *
-*  This class is a backport of the corresponding class of FLOW3. 
+*  This class is a backport of the corresponding class of FLOW3.
 *  All credits go to the v5 team.
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
 ***************************************************************/
 
 class Tx_Extbase_MVC_Web_RequestBuilder_testcase extends Tx_Extbase_Base_testcase {
-       
+
+       /**
+        * @var array
+        */
+       protected $getBackup = array();
+
+       /**
+        * @var array
+        */
+       protected $postBackup = array();
+
        public function __construct() {
                require_once(t3lib_extMgm::extPath('extbase', 'Classes/MVC/Web/RequestBuilder.php'));
        }
-       
+
        public function setUp() {
                $this->configuration = array(
                        'userFunc' => 'Tx_Extbase_Dispatcher->dispatch',
@@ -54,8 +64,15 @@ class Tx_Extbase_MVC_Web_RequestBuilder_testcase extends Tx_Extbase_Base_testcas
                                )
                        );
                $this->builder = new Tx_Extbase_MVC_Web_RequestBuilder;
+               $this->getBackup = $_GET;
+               $this->postBackup = $_POST;
        }
-       
+
+       public function tearDown() {
+               $_GET = $this->getBackup;
+               $_POST = $this->postBackup;
+       }
+
        /**
         * @test
         */
@@ -68,7 +85,7 @@ class Tx_Extbase_MVC_Web_RequestBuilder_testcase extends Tx_Extbase_Base_testcas
                $this->assertEquals('TheFirstController', $request->getControllerName());
                $this->assertEquals('show', $request->getControllerActionName());
        }
-       
+
        /**
         * @test
         */
@@ -95,7 +112,7 @@ class Tx_Extbase_MVC_Web_RequestBuilder_testcase extends Tx_Extbase_Base_testcas
                $this->assertEquals('Standard', $request->getControllerName());
                $this->assertEquals('index', $request->getControllerActionName());
        }
-       
+
        /**
         * @test
         */
@@ -120,5 +137,48 @@ class Tx_Extbase_MVC_Web_RequestBuilder_testcase extends Tx_Extbase_Base_testcas
                $this->assertEquals(t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'), $request->getRequestURI());
        }
 
+       /**
+        * @test
+        */
+       public function buildSetsParametersFromGetAndPostVariables() {
+               $builder = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_MVC_Web_RequestBuilder'), array('dummy'));
+               $builder->_set('extensionName', 'someExtensionName');
+               $builder->_set('pluginName', 'somePluginName');
+
+               $_GET = array(
+                       'tx_someotherextensionname_somepluginname' => array(
+                               'foo' => 'bar'
+                       ),
+                       'tx_someextensionname_somepluginname' => array(
+                               'parameter1' => 'valueGetsOverwritten',
+                               'parameter2' => array(
+                                       'parameter3' => 'value3'
+                               )
+                       )
+               );
+               $_POST = array(
+                       'tx_someextensionname_someotherpluginname' => array(
+                               'foo' => 'bar'
+                       ),
+                       'tx_someextensionname_somepluginname' => array(
+                               'parameter1' => 'value1',
+                               'parameter2' => array(
+                                       'parameter4' => 'value4'
+                               )
+                       )
+               );
+
+               $request = $builder->build();
+               $expectedResult = array(
+                       'parameter1' => 'value1',
+                       'parameter2' => array(
+                               'parameter3' => 'value3',
+                               'parameter4' => 'value4',
+                       ),
+               );
+               $actualResult = $request->getArguments();
+               $this->assertEquals($expectedResult, $actualResult);
+       }
+
 }
 ?>
index 3666e77..0b50265 100644 (file)
 
 
 /**
- * Testcase for class Tx_Extbase_Utility_Plugin
+ * Testcase for class Tx_Extbase_Utility_Extension
  *
  * @package Extbase
  * @subpackage extbase
  */
-class Tx_Extbase_Utility_Plugin_testcase extends tx_phpunit_testcase {
+class Tx_Extbase_Utility_Extension_testcase extends tx_phpunit_testcase {
        
        /**
         * Contains backup of $TYPO3_CONF_VARS
@@ -49,12 +49,12 @@ class Tx_Extbase_Utility_Plugin_testcase extends tx_phpunit_testcase {
        
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingTsWorksForMinimalisticSetup() {
                global $TYPO3_CONF_VARS;
                $TYPO3_CONF_VARS['FE']['defaultTypoScript_setup.'] = array();
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        'MyExtension',
                        'Pi1',
                        'My Plugin Title',
@@ -73,12 +73,12 @@ class Tx_Extbase_Utility_Plugin_testcase extends tx_phpunit_testcase {
        
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingTsAddsEnablesCacheClearingByDefault() {
                global $TYPO3_CONF_VARS;
                $TYPO3_CONF_VARS['FE']['defaultTypoScript_setup.'] = array();
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        'MyExtension',
                        'Pi1',
                        'My Plugin Title',
@@ -93,12 +93,12 @@ class Tx_Extbase_Utility_Plugin_testcase extends tx_phpunit_testcase {
        
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingTsWorksForASingleControllerAction() {
                global $TYPO3_CONF_VARS;
                $TYPO3_CONF_VARS['FE']['defaultTypoScript_setup.'] = array();
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        'MyExtension',
                        'Pi1',
                        'My Plugin Title',
@@ -120,11 +120,11 @@ class Tx_Extbase_Utility_Plugin_testcase extends tx_phpunit_testcase {
 
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingPluginWithEmptyPluginNameResultsInAnError() {
                $this->setExpectedException('InvalidArgumentException');
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        'MyExtension',
                        '',
                        'My Plugin Title',
@@ -136,11 +136,11 @@ class Tx_Extbase_Utility_Plugin_testcase extends tx_phpunit_testcase {
 
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingPluginWithEmptyExtensionNameResultsInAnError() {
                $this->setExpectedException('InvalidArgumentException');
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        '',
                        'Pi1',
                        'My Plugin Title',
@@ -152,12 +152,12 @@ class Tx_Extbase_Utility_Plugin_testcase extends tx_phpunit_testcase {
 
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingPluginRespectsDefaultActionAsANonCachableAction() {
                global $TYPO3_CONF_VARS;
                $TYPO3_CONF_VARS['FE']['defaultTypoScript_setup.'] = array();
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        'MyExtension',
                        'Pi1',
                        'My Plugin Title',
@@ -180,12 +180,12 @@ tt_content.list.20.myextension_pi1 = USER', $staticTypoScript);
 
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingPluginRespectsNonDefaultActionAsANonCachableAction() {
                global $TYPO3_CONF_VARS;
                $TYPO3_CONF_VARS['FE']['defaultTypoScript_setup.'] = array();
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        'MyExtension',
                        'Pi1',
                        'My Plugin Title',
@@ -208,12 +208,12 @@ tt_content.list.20.myextension_pi1 = USER_INT', $staticTypoScript);
 
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingPluginWorksForMultipleControllerActionsWithCachableActionAsDefault() {
                global $TYPO3_CONF_VARS;
                $TYPO3_CONF_VARS['FE']['defaultTypoScript_setup.'] = array();
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        'MyExtension',
                        'Pi1',
                        'My Plugin Title',
@@ -251,12 +251,12 @@ tt_content.list.20.myextension_pi1 = USER_INT', $staticTypoScript);
 
        /**
         * @test
-        * @see Tx_Extbase_Utility_Plugin::registerPlugin
+        * @see Tx_Extbase_Utility_Extension::registerPlugin
         */
        public function addingPluginWorksForMultipleControllerActionsWithNonCachableActionAsDefault() {
                global $TYPO3_CONF_VARS;
                $TYPO3_CONF_VARS['FE']['defaultTypoScript_setup.'] = array();
-               Tx_Extbase_Utility_Plugin::registerPlugin(
+               Tx_Extbase_Utility_Extension::registerPlugin(
                        'MyExtension',
                        'Pi1',
                        'My Plugin Title',
@@ -290,12 +290,12 @@ tt_content.list.20.myextension_pi1 = USER', $staticTypoScript);
 
                /**
                 * @test
-                * @see Tx_Extbase_Utility_Plugin::registerPlugin
+                * @see Tx_Extbase_Utility_Extension::registerPlugin
                 */
                public function addingPluginWorksForMultipleControllerActionsWithNonCachableActionAsDefaultAndOnlyNonCachableActions() {
                        global $TYPO3_CONF_VARS;
                        $TYPO3_CONF_VARS['FE']['defaultTypoScript_setup.'] = array();
-                       Tx_Extbase_Utility_Plugin::registerPlugin(
+                       Tx_Extbase_Utility_Extension::registerPlugin(
                                'MyExtension',
                                'Pi1',
                                'My Plugin Title',
index 65f00e7..64c1f85 100644 (file)
@@ -208,7 +208,6 @@ return array(
        'tx_extbase_reflection_service' => $extensionClassesPath . 'Reflection/Service.php',
        'tx_extbase_utility_arrays' => $extensionClassesPath . 'Utility/Arrays.php',
        'tx_extbase_utility_extension' => $extensionClassesPath . 'Utility/Extension.php',
-       'tx_extbase_utility_plugin' => $extensionClassesPath . 'Utility/Plugin.php',
        'tx_extbase_utility_typoscript' => $extensionClassesPath . 'Utility/TypoScript.php',
        'tx_extbase_validation_error' => $extensionClassesPath . 'Validation/Error.php',
        'tx_extbase_validation_exception' => $extensionClassesPath . 'Validation/Exception.php',
index dc74be1..0f5e793 100644 (file)
@@ -2,7 +2,7 @@
 if (!defined ('TYPO3_MODE'))   die ('Access denied.');
 
 require_once(t3lib_extMgm::extPath('extbase') . 'Classes/Dispatcher.php');
-require_once(t3lib_extMgm::extPath('extbase') . 'Classes/Utility/Plugin.php');
+require_once(t3lib_extMgm::extPath('extbase') . 'Classes/Utility/Extension.php');
 
 // use own cache table
 $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_extbase_reflection'] = array(