[~TASK] Extbase (Persistence): Heavily refactored DataMap building process. Implement...
authorJochen Rau <j.rau@web.de>
Tue, 30 Mar 2010 09:28:54 +0000 (09:28 +0000)
committerJochen Rau <j.rau@web.de>
Tue, 30 Mar 2010 09:28:54 +0000 (09:28 +0000)
[~TASK] Extbase (Reflection): Improved handling of array to be accessed via ObjectAccessors.

typo3/sysext/extbase/Classes/DomainObject/AbstractEntity.php
typo3/sysext/extbase/Classes/Persistence/Backend.php
typo3/sysext/extbase/Classes/Persistence/LazyObjectStorage.php
typo3/sysext/extbase/Classes/Persistence/Mapper/ColumnMap.php
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMap.php
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapFactory.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapper.php
typo3/sysext/extbase/Classes/Persistence/Storage/Typo3DbBackend.php
typo3/sysext/extbase/Classes/Reflection/ObjectAccess.php
typo3/sysext/extbase/Tests/Persistence/Mapper/DataMapFactory_testcase.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Persistence/Mapper/DataMap_testcase.php [deleted file]

index 621cde6..e5c3eba 100644 (file)
@@ -52,9 +52,8 @@ abstract class Tx_Extbase_DomainObject_AbstractEntity extends Tx_Extbase_DomainO
                        $this->_cleanProperties = array();
                        $properties = get_object_vars($this);
                        foreach ($properties as $propertyName => $propertyValue) {
-                               if ($dataMapper->isPersistableProperty(get_class($this), $propertyName)) {
-                                       $this->_memorizePropertyCleanState($propertyName);
-                               }
+                               if ($propertyName[0] === '_') continue; // Do not memorize "internal" properties
+                               $this->_memorizePropertyCleanState($propertyName);
                        }
                }
        }
index 14a33fe..d02d2dc 100644 (file)
@@ -390,10 +390,10 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                                                        $this->persistValueObject($propertyValue);
                                                }
                                        }
-                                       $row[$columnMap->getColumnName()] = $dataMap->convertPropertyValueToFieldValue($propertyValue);
+                                       $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue);
                                }
                        } elseif ($object instanceof Tx_Extbase_DomainObject_AbstractValueObject || $object->_isNew() || $object->_isDirty($propertyName)) {
-                               $row[$columnMap->getColumnName()] = $dataMap->convertPropertyValueToFieldValue($propertyValue);
+                               $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue);
                        }
                }
 
@@ -477,7 +477,7 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                                $propertyType = $propertyMetaData['type'];
                                // FIXME enable property-type check
                                // $this->checkPropertyType($propertyType, $propertyValue);
-                               $row[$columnMap->getColumnName()] = $dataMap->convertPropertyValueToFieldValue($propertyValue);
+                               $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue);
                        }
                        $this->insertObject($object, $row);
                }
@@ -802,13 +802,13 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
        protected function addCommonFieldsToRow(Tx_Extbase_DomainObject_DomainObjectInterface $object, array &$row) {
                $className = get_class($object);
                $dataMap = $this->dataMapper->getDataMap($className);
-               if ($dataMap->hasCreationDateColumn() && $object->_isNew()) {
+               if ($object->_isNew() && ($dataMap->getCreationDateColumnName() !== NULL)) {
                        $row[$dataMap->getCreationDateColumnName()] = $GLOBALS['EXEC_TIME'];
                }
-               if ($dataMap->hasTimestampColumn()) {
-                       $row[$dataMap->getTimestampColumnName()] = $GLOBALS['EXEC_TIME'];
+               if ($dataMap->getModificationDateColumnName() !== NULL) {
+                       $row[$dataMap->getModificationDateColumnName()] = $GLOBALS['EXEC_TIME'];
                }
-               if ($object->_isNew() && $dataMap->hasPidColumn() && !isset($row['pid'])) {
+               if ($object->_isNew() && !isset($row['pid'])) {
                        $row['pid'] = $this->determineStoragePageIdForNewRecord($object);
                }
        }
@@ -838,8 +838,8 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
        protected function removeObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, $markAsDeleted = TRUE) {
                $dataMap = $this->dataMapper->getDataMap(get_class($object));
                $tableName = $dataMap->getTableName();
-               if (($markAsDeleted === TRUE) && $dataMap->hasDeletedColumn()) {
-                       $deletedColumnName = $dataMap->getDeletedColumnName();
+               if (($markAsDeleted === TRUE) && ($dataMap->getDeletedFlagColumnName() !== NULL)) {
+                       $deletedColumnName = $dataMap->getDeletedFlagColumnName();
                        $res = $this->storageBackend->updateRow(
                                $tableName,
                                array(
@@ -887,19 +887,6 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
        }
 
        /**
-        * Delegates the call to the Data Map.
-        * Returns TRUE if the property is persistable (configured in $TCA)
-        *
-        * @param string $className The property name
-        * @param string $propertyName The property name
-        * @return boolean TRUE if the property is persistable (configured in $TCA)
-        */
-       public function isPersistableProperty($className, $propertyName) {
-               $dataMap = $this->dataMapper->getDataMap($className);
-               return $dataMap->isPersistableProperty($propertyName);
-       }
-       
-       /**
         * Determine the storage page ID for a given NEW record
         *
         * This does the following:
@@ -920,6 +907,24 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                        return (int) $storagePidList[0];
                }
        }
+       
+       /**
+        * Returns a plain value, i.e. objects are flattened out if possible.
+        *
+        * @param mixed $input
+        * @return mixed
+        */
+       protected function getPlainValue($input) {
+               if ($input instanceof DateTime) {
+                       return $input->format('U');
+               } elseif ($input instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
+                       return $input->getUid();
+               } elseif (is_bool($input)) {
+                       return $input === TRUE ? 1 : 0;
+               } else {
+                       return $input;
+               }
+       }
 
 }
 
index 9097053..04c6cbf 100644 (file)
@@ -104,8 +104,6 @@ class Tx_Extbase_Persistence_LazyObjectStorage extends Tx_Extbase_Persistence_Ob
                $columnMap = $dataMapper->getDataMap(get_class($this->parentObject))->getColumnMap($this->propertyName);
                $numberOfElements = NULL;
                if ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
-                       $parentKeyFieldName = $columnMap->getParentKeyFieldName();
-                       $dataMapper = Tx_Extbase_Dispatcher::getPersistenceManager()->getBackend()->getDataMapper();
                        $numberOfElements = $dataMapper->countRelated($this->parentObject, $this->propertyName, $this->fieldValue);
                } else {
                        $this->initializeStorage();
index 20e039d..214f32a 100644 (file)
@@ -42,6 +42,14 @@ class Tx_Extbase_Persistence_Mapper_ColumnMap {
        const RELATION_HAS_AND_BELONGS_TO_MANY = 'RELATION_HAS_AND_BELONGS_TO_MANY';
 
        /**
+        * Constants reflecting how the relation information is stored
+        */
+       const RELATION_PARENT_FOREIGN_KEY = 'RELATION_PARENT_FOREIGN_KEY';
+       const RELATION_CHILD_FOREIGN_KEY = 'RELATION_CHILD_FOREIGN_KEY';
+       const RELATION_PARENT_CSV = 'RELATION_PARENT_CSV';
+       const RELATION_INTERMEDIATE_TABLE = 'RELATION_INTERMEDIATE_TABLE';
+
+       /**
         * Constants reflecting the loading strategy
         */
        const STRATEGY_EAGER = 'eager';
@@ -167,63 +175,13 @@ class Tx_Extbase_Persistence_Mapper_ColumnMap {
        }
 
        public function setTypeOfRelation($typeOfRelation) {
-               switch ($typeOfRelation) {
-                       case self::RELATION_NONE;
-                       case self::RELATION_HAS_ONE;
-                       case self::RELATION_HAS_MANY;
-                       case self::RELATION_BELONGS_TO_MANY;
-                       case self::RELATION_HAS_AND_BELONGS_TO_MANY;
-                               $this->typeOfRelation = $typeOfRelation;
-                               break;
-                       default:
-                               $this->typeOfRelation = NULL;
-                               break;
-               }
-       }
-
-       public function isRelation() {
-               return $this->typeOfRelation !== NULL && $this->typeOfRelation !== self::RELATION_NONE;
+               $this->typeOfRelation = $typeOfRelation;
        }
 
        public function getTypeOfRelation() {
                return $this->typeOfRelation;
        }
 
-       public function setPropertyType($propertyType) {
-               switch ($propertyType) {
-                       case Tx_Extbase_Persistence_PropertyType::UNDEFINED;
-                       case Tx_Extbase_Persistence_PropertyType::STRING;
-                       case Tx_Extbase_Persistence_PropertyType::DATE;
-                       case Tx_Extbase_Persistence_PropertyType::LONG;
-                       case Tx_Extbase_Persistence_PropertyType::DOUBLE;
-                       case Tx_Extbase_Persistence_PropertyType::BOOLEAN;
-                       case Tx_Extbase_Persistence_PropertyType::REFERENCE;
-                               $this->propertyType = $propertyType;
-                               break;
-                       default:
-                               $this->propertyType = Tx_Extbase_Persistence_PropertyType::UNDEFINED;
-                               break;
-               }
-       }
-
-       public function getPropertyType() {
-               return $this->propertyType;
-       }
-
-       public function setLoadingStrategy($loadingStrategy) {
-               switch ($loadingStrategy) {
-                       case self::STRATEGY_LAZY_PROXY;
-                       case self::STRATEGY_LAZY_STORAGE;
-                       case self::STRATEGY_EAGER;
-                               $this->loadingStrategy = $loadingStrategy;
-                               break;
-               }
-       }
-
-       public function getLoadingStrategy() {
-               return $this->loadingStrategy;
-       }
-
        public function setPropertyName($propertyName) {
                $this->propertyName = $propertyName;
        }
index c269be3..00634da 100644 (file)
@@ -32,7 +32,7 @@
 class Tx_Extbase_Persistence_Mapper_DataMap {
 
        /**
-        * The domain class name
+        * The class name
         *
         * @var string
         **/
@@ -51,21 +51,55 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         * @var array
         **/
        protected $columnMaps;
+               
+       /**
+        * @var string
+        **/
+       protected $modificationDateColumnName;
+
+       /**
+        * @var string
+        **/
+       protected $creationDateColumnName;
+
+       /**
+        * @var string
+        **/
+       protected $creatorColumnName;
+
+       /**
+        * @var string
+        **/
+       protected $deletedFlagColumnName;
+
+       /**
+        * @var string
+        **/
+       protected $disabledFlagColumnName;
+       
+       /**
+        * @var string
+        **/
+       protected $startTimeColumnName;
+
+       /**
+        * @var string
+        **/
+       protected $endTimeColumnName;
+
+       /**
+        * @var string
+        **/
+       protected $frontendUserGroupColumnName;
 
        /**
         * Constructs this DataMap
         *
         * @param string $className The class name. This determines the table to fetch the configuration for
         */
-       // TODO Refactor to factory pattern (DataMapFactory) and value object (DataMap)
-       public function __construct($className, $tableName = '', array $mapping = array()) {
+       public function __construct($className, $tableName) {
                $this->setClassName($className);
-               if (empty($tableName)) {
-                       $this->setTableName(strtolower($className));
-               } else {
-                       $this->setTableName($tableName);
-               }
-               $this->initialize($mapping);
+               $this->setTableName($tableName);
        }
 
        /**
@@ -105,223 +139,6 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
        }
        
        /**
-        * Initializes the data map by adding column maps for all the configured columns in the $TCA.
-        * It also resolves the type of values the column is holding and the typo of relation the column
-        * represents.
-        *
-        * @return void
-        */
-       protected function initialize(array $mapping) {
-               $this->addCommonColumns();
-               $columnConfigurations = array();
-               foreach ($this->getColumnsDefinition() as $columnName => $columnDefinition) {
-                       $columnConfigurations[$columnName] = $columnDefinition['config'];
-                       $columnConfigurations[$columnName]['mapOnProperty'] = Tx_Extbase_Utility_Extension::convertUnderscoredToLowerCamelCase($columnName);
-               }
-               $columnConfigurations = t3lib_div::array_merge_recursive_overrule($columnConfigurations, $mapping);
-               foreach ($columnConfigurations as $columnName => $columnConfiguration) {
-                       $columnMap = new Tx_Extbase_Persistence_Mapper_ColumnMap($columnName, $columnConfiguration['mapOnProperty']);
-                       $this->setPropertyType($columnMap, $columnConfiguration);
-                       $this->setRelations($columnMap, $columnConfiguration);
-                       $this->addColumnMap($columnMap);
-               }
-       }
-
-       /**
-        * Returns the TCA columns array of the specified table
-        *
-        * @param string $tableName An optional table name to fetch the columns definition from
-        * @return array The TCA columns definition
-        */
-       public function getColumnsDefinition($tableName = '') {
-               $tableName = strlen($tableName) > 0 ? $tableName : $this->getTableName();
-               if (TYPO3_MODE === 'FE') {
-                       $GLOBALS['TSFE']->includeTCA();
-               }
-               t3lib_div::loadTCA($tableName);
-               $columns = is_array($GLOBALS['TCA'][$tableName]['columns']) ? $GLOBALS['TCA'][$tableName]['columns'] : array();
-               return $columns;
-       }       
-
-       /**
-        * Adds available common columns (e.g. tstamp or crdate) to the data map. It takes the configured column names
-        * into account.
-        *
-        * @return void
-        */
-       protected function addCommonColumns() {
-               $this->addColumn('uid', NULL, Tx_Extbase_Persistence_PropertyType::LONG);
-               if ($this->hasPidColumn()) {
-                       $this->addColumn('pid', NULL, Tx_Extbase_Persistence_PropertyType::LONG);
-               }
-               if ($this->hasTimestampColumn()) {
-                       $this->addColumn($this->getTimestampColumnName(), NULL, Tx_Extbase_Persistence_PropertyType::DATE);
-               }
-               if ($this->hasCreationDateColumn()) {
-                       $this->addColumn($this->getCreationDateColumnName(), NULL, Tx_Extbase_Persistence_PropertyType::DATE);
-               }
-               if ($this->hasCreatorUidColumn()) {
-                       $this->addColumn($this->getCreatorUidColumnName(), NULL, Tx_Extbase_Persistence_PropertyType::LONG);
-               }
-               if ($this->hasDeletedColumn()) {
-                       $this->addColumn($this->getDeletedColumnName(), NULL, Tx_Extbase_Persistence_PropertyType::BOOLEAN);
-               }
-               if ($this->hasHiddenColumn()) {
-                       $this->addColumn($this->getHiddenColumnName(), NULL, Tx_Extbase_Persistence_PropertyType::BOOLEAN);
-               }
-       }
-
-       /**
-        * This method tries to determine the type of value the column hold by inspectiong the $TCA column configuration
-        * and sets it.
-        *
-        * @param string $columnMap The column map
-        * @param string $columnConfiguration The column configuration from $TCA
-        * @return void
-        */
-       protected function setPropertyType(Tx_Extbase_Persistence_Mapper_ColumnMap &$columnMap, $columnConfiguration) {
-               $evalConfiguration = t3lib_div::trimExplode(',', $columnConfiguration['eval']);
-               if (in_array('date', $evalConfiguration) || in_array('datetime', $evalConfiguration)) {
-                       $columnMap->setPropertyType(Tx_Extbase_Persistence_PropertyType::DATE);
-               } elseif ($columnConfiguration['type'] === 'check' && empty($columnConfiguration['items'])) {
-                       $columnMap->setPropertyType(Tx_Extbase_Persistence_PropertyType::BOOLEAN);
-               } elseif (in_array('int', $evalConfiguration)) {
-                       $columnMap->setPropertyType(Tx_Extbase_Persistence_PropertyType::LONG);
-               } elseif (in_array('double2', $evalConfiguration)) {
-                       $columnMap->setPropertyType(Tx_Extbase_Persistence_PropertyType::DOUBLE);
-               } else {
-                       if (isset($columnConfiguration['foreign_table'])) {
-                               if (isset($columnConfiguration['loadingStrategy'])) {
-                                       $columnMap->setLoadingStrategy($columnConfiguration['loadingStrategy']);
-                               } else {
-                                       $columnMap->setLoadingStrategy(Tx_Extbase_Persistence_Mapper_ColumnMap::STRATEGY_EAGER);
-                               }
-                               $columnMap->setPropertyType(Tx_Extbase_Persistence_PropertyType::REFERENCE);
-                       } else {
-                               $columnMap->setPropertyType(Tx_Extbase_Persistence_PropertyType::STRING);
-                       }
-               }
-       }
-
-       /**
-        * This method tries to determine the type of type of relation to other tables and sets it based on
-        * the $TCA column configuration
-        *
-        * @param Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap The column map
-        * @param string $columnConfiguration The column configuration from $TCA
-        * @return void
-        */
-       protected function setRelations(Tx_Extbase_Persistence_Mapper_ColumnMap &$columnMap, $columnConfiguration) {
-               if (isset($columnConfiguration) && $columnConfiguration['type'] !== 'passthrough') {
-                       if (isset($columnConfiguration['foreign_table'])) {
-                               if (isset($columnConfiguration['MM']) || isset($columnConfiguration['foreign_selector'])) {
-                                       $this->setManyToManyRelation($columnMap, $columnConfiguration);
-                               } else {
-                                       if ($columnConfiguration['maxitems'] == 1) {
-                                               $this->setOneToOneRelation($columnMap, $columnConfiguration);
-                                       } else {
-                                               $this->setOneToManyRelation($columnMap, $columnConfiguration);
-                                       }
-                               }
-                       } else {
-                               $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_NONE);
-                       }
-               }
-       }
-       
-       /**
-        * This method sets the configuration for a 1:1 relation based on
-        * the $TCA column configuration
-        *
-        * @param string $columnMap The column map
-        * @param string $columnConfiguration The column configuration from $TCA
-        * @return void
-        */
-       protected function setOneToOneRelation(Tx_Extbase_Persistence_Mapper_ColumnMap &$columnMap, $columnConfiguration) {
-               $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE);
-               $columnMap->setChildTableName($columnConfiguration['foreign_table']);
-               $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
-               $columnMap->setChildSortbyFieldName($columnConfiguration['foreign_sortby']);
-               $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
-               $columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field']);
-       }
-       
-       /**
-        * This method sets the configuration for a 1:n relation based on
-        * the $TCA column configuration
-        *
-        * @param string $columnMap The column map
-        * @param string $columnConfiguration The column configuration from $TCA
-        * @return void
-        */
-       protected function setOneToManyRelation(Tx_Extbase_Persistence_Mapper_ColumnMap &$columnMap, $columnConfiguration) {
-               $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY);
-               $columnMap->setChildTableName($columnConfiguration['foreign_table']);
-               $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
-               $columnMap->setChildSortbyFieldName($columnConfiguration['foreign_sortby']);
-               $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
-               $columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field']);
-       }
-       
-       /**
-        * This method sets the configuration for a m:n relation based on
-        * the $TCA column configuration
-        *
-        * @param string $columnMap The column map
-        * @param string $columnConfiguration The column configuration from $TCA
-        * @return void
-        */
-       protected function setManyToManyRelation(Tx_Extbase_Persistence_Mapper_ColumnMap &$columnMap, $columnConfiguration) {
-               // TODO support multi table relationships
-               $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY);
-               if (isset($columnConfiguration['MM'])) {
-                       $columnMap->setChildTableName($columnConfiguration['foreign_table']);
-                       $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
-                       $columnMap->setRelationTableName($columnConfiguration['MM']);
-                       if (is_array($columnConfiguration['MM_match_fields'])) {
-                               $columnMap->setRelationTableMatchFields($columnConfiguration['MM_match_fields']);
-                       }
-                       if (is_array($columnConfiguration['MM_insert_fields'])) {
-                               $columnMap->setRelationTableInsertFields($columnConfiguration['MM_insert_fields']);
-                       }
-                       $columnMap->setRelationTableWhereStatement($columnConfiguration['MM_table_where']);
-                       if (!empty($columnConfiguration['MM_opposite_field'])) {
-                               $columnMap->setParentKeyFieldName('uid_foreign');
-                               $columnMap->setChildKeyFieldName('uid_local');
-                               $columnMap->setChildSortByFieldName('sorting_foreign');
-                       } else {
-                               $columnMap->setParentKeyFieldName('uid_local');
-                               $columnMap->setChildKeyFieldName('uid_foreign');
-                               $columnMap->setChildSortByFieldName('sorting');
-                       }
-               } elseif (isset($columnConfiguration['foreign_selector'])) {
-                       $columns = $this->getColumnsDefinition($columnConfiguration['foreign_table']);
-                       if (isset($columnConfiguration['foreign_selector'])) {
-                               $childKeyFieldName = $columnConfiguration['foreign_selector'];
-                       } else {
-                               $childKeyFieldName = 'uid_foreign';
-                       }
-                       $columnMap->setChildTableName($columns[$childKeyFieldName]['config']['foreign_table']);
-                       $columnMap->setRelationTableName($columnConfiguration['foreign_table']);
-                       $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
-                       $columnMap->setChildKeyFieldName($childKeyFieldName);
-                       $columnMap->setChildSortByFieldName($columnConfiguration['foreign_sortby']);
-               } else {
-                       throw new Tx_Extbase_Persistence_Exception_UnsupportedRelation('The given information to build a many-to-many-relation was not sufficient. Check your TCA definitions. mm-relations with IRRE must have at least a defined "MM" or "foreign_selector".', 1268817963);
-               }
-       }
-       
-       /**
-        * Sets the column maps.
-        *
-        * @param array $columnMaps The column maps stored in a flat array.
-        * @return void
-        */
-       public function setColumnMaps(array $columnMaps) {
-               $this->columnMaps = $columnMaps;
-       }
-
-       /**
         * Adds a given column map to the data map.
         *
         * @param Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap The column map
@@ -330,38 +147,7 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
        public function addColumnMap(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap) {
                $this->columnMaps[$columnMap->getPropertyName()] = $columnMap;
        }
-
-       /**
-        * Builds a column map out of the given column name, type of value (optional), and type of
-        * relation (optional) and adds it to the data map.
-        *
-        * @param string $columnName The column name
-        * @param string $propertyName The property name
-        * @param string $propertyType The type of value (default: string)
-        * @param string $typeOfRelation The type of relation (default: none)
-        * @return Tx_Extbase_Persistence_Mapper_DataMap Returns itself for a fluent interface
-        */
-       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_Extension::convertUnderscoredToLowerCamelCase($columnName);
-               }
-
-               $columnMap = new Tx_Extbase_Persistence_Mapper_ColumnMap($columnName, $propertyName);
-               $columnMap->setPropertyType($propertyType);
-               $columnMap->setTypeOfRelation($typeOfRelation);
-               $this->addColumnMap($columnMap);
-               return $this;
-       }
-
-       /**
-        * Returns all column maps
-        *
-        * @return array The column maps
-        */
-       public function getColumnMaps() {
-               return $this->columnMaps;
-       }
-
+       
        /**
         * Returns the column map corresponding to the given property name.
         *
@@ -381,61 +167,53 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
        public function isPersistableProperty($propertyName) {
                return isset($this->columnMaps[$propertyName]);
        }
-
-       /**
-        * Check if versioning is enabled .
-        *
-        * @return boolean
-        */
-       public function isVersionable() {
-               return ($GLOBALS['TCA'] [$this->tableName] ['ctrl'] ['versioningWS'] === '1');
-       }
-
+       
        /**
-        * Returns TRUE if the table has a pid column holding the id of the page the record is virtually stored on.
-        * Currently we don't support tables without a pid column.
+        * Sets the name of a column holding the timestamp the record was modified
         *
-        * @return boolean The result
+        * @param string The field name
+        * @return void
         */
-       public function hasPidColumn() {
-               // TODO Should we implement a check for having a pid column?
-               return TRUE;
+       public function setModificationDateColumnName($modificationDateColumnName) {
+               $this->modificationDateColumnName = $modificationDateColumnName;
        }
-
+       
        /**
         * Returns the name of a column holding the timestamp the record was modified
         *
         * @return string The field name
         */
-       public function getTimestampColumnName() {
-               return $GLOBALS['TCA'][$this->getTableName()]['ctrl']['tstamp'];
+       public function getModificationDateColumnName() {
+               return $this->modificationDateColumnName;
        }
-
+       
        /**
-        * Returns TRUE if the table has a column holding the timestamp the record was modified
+        * Sets the name of a column holding the creation date timestamp
         *
-        * @return boolean The result
+        * @param string The field name
+        * @return void
         */
-       public function hasTimestampColumn() {
-               return !empty($GLOBALS['TCA'][$this->getTableName()]['ctrl']['tstamp']);
+       public function setCreationDateColumnName($creationDateColumnName) {
+               $this->creationDateColumnName = $creationDateColumnName;
        }
-
+       
        /**
         * Returns the name of a column holding the creation date timestamp
         *
         * @return string The field name
         */
        public function getCreationDateColumnName() {
-               return $GLOBALS['TCA'][$this->getTableName()]['ctrl']['crdate'];
+               return $this->creationDateColumnName;
        }
-
+       
        /**
-        * Returns TRUE if the table has olumn holding the creation date timestamp
+        * Sets the name of a column holding the uid of the back-end user who created this record
         *
-        * @return boolean The result
+        * @param string The field name
+        * @return void
         */
-       public function hasCreationDateColumn() {
-               return !empty($GLOBALS['TCA'][$this->getTableName()]['ctrl']['crdate']);
+       public function setCreatorColumnName($creatorColumnName) {
+               $this->creatorColumnName = $creatorColumnName;
        }
 
        /**
@@ -443,53 +221,56 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         *
         * @return string The field name
         */
-       public function getCreatorUidColumnName() {
-               return $GLOBALS['TCA'][$this->getTableName()]['ctrl']['cruser_id'];
+       public function getCreatorColumnName() {
+               return $this->creatorColumnName;
        }
 
        /**
-        * Returns TRUE if the table has a column holding the uid of the back-end user who created this record
+        * Sets the name of a column indicating the 'deleted' state of the row
         *
-        * @return boolean The result
+        * @param string The field name
+        * @return void
         */
-       public function hasCreatorUidColumn() {
-               return !empty($GLOBALS['TCA'][$this->getTableName()]['ctrl']['cruser_id']);
+       public function setDeletedFlagColumnName($deletedFlagColumnName) {
+               $this->deletedFlagColumnName = $deletedFlagColumnName;
        }
-
+       
        /**
         * Returns the name of a column indicating the 'deleted' state of the row
         *
         * @return string The field name
         */
-       public function getDeletedColumnName() {
-               return $GLOBALS['TCA'][$this->getTableName()]['ctrl']['delete'];
+       public function getDeletedFlagColumnName() {
+               return $this->deletedFlagColumnName;
        }
-
+       
        /**
-        * Returns TRUE if the table has a column indicating the 'deleted' state of the row
+        * Sets the name of a column indicating the 'hidden' state of the row
         *
-        * @return boolean The result
+        * @param string The field name
+        * @return void
         */
-       public function hasDeletedColumn() {
-               return !empty($GLOBALS['TCA'][$this->getTableName()]['ctrl']['delete']);
+       public function setDisabledFlagColumnName($disabledFlagColumnName) {
+               $this->disabledFlagColumnName = $disabledFlagColumnName;
        }
-
+       
        /**
         * Returns the name of a column indicating the 'hidden' state of the row
         *
         * @return string The field name
         */
-       public function getHiddenColumnName() {
-               return $GLOBALS['TCA'][$this->getTableName()]['ctrl']['enablecolumns']['disabled'];
+       public function getDisabledFlagColumnName() {
+               return $this->disabledFlagColumnName;
        }
-
+       
        /**
-        * Returns TRUE if the table has a column indicating the 'hidden' state of the row
+        * Sets the name of a column holding the timestamp the record should not displayed before
         *
-        * @return boolean The result
+        * @param string The field name
+        * @return void
         */
-       public function hasHiddenColumn() {
-               return !empty($GLOBALS['TCA'][$this->getTableName()]['ctrl']['enablecolumns']['disabled']);
+       public function setStartTimeColumnName($startTimeColumnName) {
+               $this->startTimeColumnName = $startTimeColumnName;
        }
 
        /**
@@ -498,16 +279,17 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         * @return string The field name
         */
        public function getStartTimeColumnName() {
-               return $GLOBALS['TCA'][$this->getTableName()]['ctrl']['enablecolumns']['starttime'];
+               return $this->startTimeColumnName;
        }
 
        /**
-        * Returns TRUE if the table has a column holding the timestamp the record should not displayed before
+        * Sets the name of a column holding the timestamp the record should not displayed afterwards
         *
-        * @return boolean The result
+        * @param string The field name
+        * @return void
         */
-       public function hasStartTimeColumn() {
-               return !empty($GLOBALS['TCA'][$this->getTableName()]['ctrl']['enablecolumns']['starttime']);
+       public function setEndTimeColumnName($endTimeColumnName) {
+               $this->endTimeColumnName = $endTimeColumnName;
        }
 
        /**
@@ -516,16 +298,17 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         * @return string The field name
         */
        public function getEndTimeColumnName() {
-               return $GLOBALS['TCA'][$this->getTableName()]['ctrl']['enablecolumns']['endtime'];
+               return $this->endTimeColumnName;
        }
 
        /**
-        * Returns TRUE if the table has a column holding the timestamp the record should not displayed afterwards
+        * Sets the name of a column holding the uid of the front-end user group which is allowed to edit this record
         *
-        * @return boolean The result
+        * @param string The field name
+        * @return void
         */
-       public function hasEndTimeColumn() {
-               return !empty($GLOBALS['TCA'][$this->getTableName()]['ctrl']['enablecolumns']['endtime']);
+       public function setFrontEndUserGroupColumnName($frontendUserGroupColumnName) {
+               $this->frontendUserGroupColumnName = $frontendUserGroupColumnName;
        }
 
        /**
@@ -534,87 +317,7 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         * @return string The field name
         */
        public function getFrontEndUserGroupColumnName() {
-               return $GLOBALS['TCA'][$this->getTableName()]['ctrl']['enablecolumns']['fe_group'];
-       }
-
-       /**
-        * Returns TRUE if the table has a column holding the uid of the front-end user group which is allowed to edit this record
-        *
-        * @return boolean The result
-        */
-       public function hasFrontEndUserGroupColumn() {
-               return !empty($GLOBALS['TCA'][$this->getTableName()]['ctrl']['enablecolumns']['fe_group']);
-       }
-
-       /**
-        * Converts a field name to the property name. It respects property name aliases defined in $TCA.
-        *
-        * @param string $fieldName The field name
-        * @return string $propertyName The property name
-        */
-       public function convertFieldNameToPropertyName($fieldName) {
-               $propertyName = $fieldName;
-               return $propertyName; // TODO Implement aliases for field names (see also convertPropertyNameToFieldName())
-       }
-
-       /**
-        * Converts a preoperty name to the field name. It respects property name aliases defined in $TCA.
-        *
-        * @param string $fieldName The field name
-        * @return string $propertyName The property name
-        */
-       public function convertPropertyNameToFieldName($propertyName) {
-               $fieldName = $propertyName;
-               return $fieldName;
-       }
-
-       /**
-        * Converts the given string into the given type
-        *
-        * @param integer $type one of the constants defined in Tx_Extbase_Persistence_PropertyType
-        * @param string $string a string representing a value of the given type
-        *
-        * @return string|int|float|DateTime|boolean
-        */
-       public function convertFieldValueToPropertyValue($type, $string) {
-               switch ($type) {
-                       case Tx_Extbase_Persistence_PropertyType::LONG:
-                               return (int) $string;
-                       case Tx_Extbase_Persistence_PropertyType::DOUBLE:
-                       case Tx_Extbase_Persistence_PropertyType::DECIMAL:
-                               return (float) $string;
-                       case Tx_Extbase_Persistence_PropertyType::DATE:
-                               if (empty($string)) { // 0 -> NULL !!!
-                                       return NULL;
-                               } else {
-                                       return new DateTime(date('c', $string));
-                               }
-                       case Tx_Extbase_Persistence_PropertyType::BOOLEAN:
-                               return (boolean) $string;
-                       default:
-                               return $string;
-               }
-       }
-
-       /**
-        * Converts a value from a property type to a database field type
-        *
-        * @param mixed $propertyValue The property value
-        * @return mixed The converted value
-        */
-       public function convertPropertyValueToFieldValue($propertyValue) {
-               if (is_bool($propertyValue)) {
-                       $convertedValue = $propertyValue ? 1 : 0;
-               } elseif ($propertyValue instanceof Tx_Extbase_DomainObject_AbstractDomainObject) {
-                       $convertedValue = $propertyValue->getUid();
-               } elseif ($propertyValue instanceof DateTime) {
-                       $convertedValue = $propertyValue->format('U');
-               } elseif (is_int($propertyValue)) {
-                       $convertedValue = $propertyValue;
-               } else {
-                       $convertedValue = $propertyValue;
-               }
-               return $convertedValue;
+               return $this->frontendUserGroupColumnName;
        }
 
 }
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapFactory.php b/typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapFactory.php
new file mode 100644 (file)
index 0000000..383bd80
--- /dev/null
@@ -0,0 +1,227 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  All rights reserved
+ *
+ *  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 factory for a data map to map a single table configured in $TCA on a domain object.
+ *
+ * @package Extbase
+ * @subpackage Persistence\Mapper
+ * @version $ID:$
+ */
+class Tx_Extbase_Persistence_Mapper_DataMapFactory {
+
+       /**
+        * Builds a data map by adding column maps for all the configured columns in the $TCA.
+        * It also resolves the type of values the column is holding and the typo of relation the column
+        * represents.
+        *
+        * @return void
+        */
+       public function buildDataMap($className) {
+               $tableName = NULL;
+               $columnMapping = array();
+               $extbaseSettings = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
+               if (is_array($extbaseSettings['persistence']['classes'][$className])) {
+                       $persistenceSettings = $extbaseSettings['persistence']['classes'][$className];
+                       if (is_string($persistenceSettings['mapping']['tableName']) && strlen($persistenceSettings['mapping']['tableName']) > 0) {
+                               $tableName = $persistenceSettings['mapping']['tableName'];
+                       }
+                       if (is_array($persistenceSettings['mapping']['columns'])) {
+                               $columnMapping = $persistenceSettings['mapping']['columns'];
+                       }
+               } elseif (class_exists($className)) {
+                       foreach (class_parents($className) as $parentClassName) {
+                               $persistenceSettings = $extbaseSettings['persistence']['classes'][$parentClassName];
+                               if (is_array($persistenceSettings)) {
+                                       if (is_string($persistenceSettings['mapping']['tableName']) && strlen($persistenceSettings['mapping']['tableName']) > 0) {
+                                               $tableName = $persistenceSettings['mapping']['tableName'];
+                                       }
+                                       if (is_array($persistenceSettings['mapping']['columns'])) {
+                                               $columnMapping = $persistenceSettings['mapping']['columns'];
+                                       }
+                               }
+                               break;
+                       }
+               }
+               if ($tableName === NULL) {
+                       $tableName = strtolower($className);
+               }
+               
+               $dataMap = t3lib_div::makeInstance('Tx_Extbase_Persistence_Mapper_DataMap', $className, $tableName);
+               $dataMap = $this->addMetaDataColumnNames($dataMap, $tableName);
+               $columnConfigurations = array();
+               foreach ($this->getColumnsDefinition($tableName) as $columnName => $columnDefinition) {
+                       $columnConfigurations[$columnName] = $columnDefinition['config'];
+                       $columnConfigurations[$columnName]['mapOnProperty'] = Tx_Extbase_Utility_Extension::convertUnderscoredToLowerCamelCase($columnName);
+               }
+               $columnConfigurations = t3lib_div::array_merge_recursive_overrule($columnConfigurations, $columnMapping);
+               foreach ($columnConfigurations as $columnName => $columnConfiguration) {
+                       $columnMap = new Tx_Extbase_Persistence_Mapper_ColumnMap($columnName, $columnConfiguration['mapOnProperty']);
+                       $columnMap = $this->setRelations($columnMap, $columnConfiguration);
+                       $dataMap->addColumnMap($columnMap);
+               }
+               // debug($dataMap);
+               return $dataMap;
+       }
+
+       /**
+        * Returns the TCA columns array of the specified table
+        *
+        * @param string $tableName An optional table name to fetch the columns definition from
+        * @return array The TCA columns definition
+        */
+       protected function getColumnsDefinition($tableName) {
+               if (TYPO3_MODE === 'FE') {
+                       $GLOBALS['TSFE']->includeTCA();
+               }
+               t3lib_div::loadTCA($tableName);
+               $columns = is_array($GLOBALS['TCA'][$tableName]['columns']) ? $GLOBALS['TCA'][$tableName]['columns'] : array();
+               return $columns;
+       }
+       
+       protected function addMetaDataColumnNames(Tx_Extbase_Persistence_Mapper_DataMap $dataMap, $tableName) {
+               $controlSection = $GLOBALS['TCA'][$tableName]['ctrl'];
+               if (isset($controlSection['tstamp'])) $dataMap->setModificationDateColumnName($controlSection['tstamp']);
+               if (isset($controlSection['crdate'])) $dataMap->setCreationDateColumnName($controlSection['crdate']);
+               if (isset($controlSection['cruser_id'])) $dataMap->setCreatorColumnName($controlSection['cruser_id']);
+               if (isset($controlSection['delete'])) $dataMap->setDeletedFlagColumnName($controlSection['delete']);
+               if (isset($controlSection['enablecolumns']['disabled'])) $dataMap->setDisabledFlagColumnName($controlSection['enablecolumns']['disabled']);
+               if (isset($controlSection['enablecolumns']['starttime'])) $dataMap->setStartTimeColumnName($controlSection['enablecolumns']['starttime']);
+               if (isset($controlSection['enablecolumns']['endtime'])) $dataMap->setEndTimeColumnName($controlSection['enablecolumns']['endtime']);
+               if (isset($controlSection['enablecolumns']['fe_group'])) $dataMap->setFrontEndUserGroupColumnName($controlSection['enablecolumns']['fe_group']);
+               return $dataMap;
+       }
+               
+       /**
+        * This method tries to determine the type of type of relation to other tables and sets it based on
+        * the $TCA column configuration
+        *
+        * @param Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap The column map
+        * @param string $columnConfiguration The column configuration from $TCA
+        * @return void
+        */
+       protected function setRelations(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, $columnConfiguration) {
+               if (isset($columnConfiguration) && $columnConfiguration['type'] !== 'passthrough') {
+                       if (isset($columnConfiguration['foreign_table'])) {
+                               if (isset($columnConfiguration['MM']) || isset($columnConfiguration['foreign_selector'])) {
+                                       $columnMap = $this->setManyToManyRelation($columnMap, $columnConfiguration);
+                               } else {
+                                       if ($columnConfiguration['maxitems'] == 1) {
+                                               $columnMap = $this->setOneToOneRelation($columnMap, $columnConfiguration);
+                                       } else {
+                                               $columnMap = $this->setOneToManyRelation($columnMap, $columnConfiguration);
+                                       }
+                               }
+                       } else {
+                               $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_NONE);
+                       }
+               }
+               return $columnMap;
+       }
+       
+       /**
+        * This method sets the configuration for a 1:1 relation based on
+        * the $TCA column configuration
+        *
+        * @param string $columnMap The column map
+        * @param string $columnConfiguration The column configuration from $TCA
+        * @return void
+        */
+       protected function setOneToOneRelation(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, $columnConfiguration) {
+               $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE);
+               $columnMap->setChildTableName($columnConfiguration['foreign_table']);
+               $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
+               $columnMap->setChildSortbyFieldName($columnConfiguration['foreign_sortby']);
+               $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
+               $columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field']);
+               return $columnMap;
+       }
+       
+       /**
+        * This method sets the configuration for a 1:n relation based on
+        * the $TCA column configuration
+        *
+        * @param string $columnMap The column map
+        * @param string $columnConfiguration The column configuration from $TCA
+        * @return void
+        */
+       protected function setOneToManyRelation(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, $columnConfiguration) {
+               $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY);
+               $columnMap->setChildTableName($columnConfiguration['foreign_table']);
+               $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
+               $columnMap->setChildSortbyFieldName($columnConfiguration['foreign_sortby']);
+               $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
+               $columnMap->setParentTableFieldName($columnConfiguration['foreign_table_field']);
+               return $columnMap;
+       }
+       
+       /**
+        * This method sets the configuration for a m:n relation based on
+        * the $TCA column configuration
+        *
+        * @param string $columnMap The column map
+        * @param string $columnConfiguration The column configuration from $TCA
+        * @return void
+        */
+       protected function setManyToManyRelation(Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap, $columnConfiguration) {
+               $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY);
+               if (isset($columnConfiguration['MM'])) {
+                       $columnMap->setChildTableName($columnConfiguration['foreign_table']);
+                       $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
+                       $columnMap->setRelationTableName($columnConfiguration['MM']);
+                       if (is_array($columnConfiguration['MM_match_fields'])) {
+                               $columnMap->setRelationTableMatchFields($columnConfiguration['MM_match_fields']);
+                       }
+                       if (is_array($columnConfiguration['MM_insert_fields'])) {
+                               $columnMap->setRelationTableInsertFields($columnConfiguration['MM_insert_fields']);
+                       }
+                       $columnMap->setRelationTableWhereStatement($columnConfiguration['MM_table_where']);
+                       if (!empty($columnConfiguration['MM_opposite_field'])) {
+                               $columnMap->setParentKeyFieldName('uid_foreign');
+                               $columnMap->setChildKeyFieldName('uid_local');
+                               $columnMap->setChildSortByFieldName('sorting_foreign');
+                       } else {
+                               $columnMap->setParentKeyFieldName('uid_local');
+                               $columnMap->setChildKeyFieldName('uid_foreign');
+                               $columnMap->setChildSortByFieldName('sorting');
+                       }
+               } elseif (isset($columnConfiguration['foreign_selector'])) {
+                       $columns = $this->getColumnsDefinition($columnConfiguration['foreign_table']);
+                       if (isset($columnConfiguration['foreign_selector'])) {
+                               $childKeyFieldName = $columnConfiguration['foreign_selector'];
+                       } else {
+                               $childKeyFieldName = 'uid_foreign';
+                       }
+                       $columnMap->setChildTableName($columns[$childKeyFieldName]['config']['foreign_table']);
+                       $columnMap->setRelationTableName($columnConfiguration['foreign_table']);
+                       $columnMap->setParentKeyFieldName($columnConfiguration['foreign_field']);
+                       $columnMap->setChildKeyFieldName($childKeyFieldName);
+                       $columnMap->setChildSortByFieldName($columnConfiguration['foreign_sortby']);
+               } else {
+                       throw new Tx_Extbase_Persistence_Exception_UnsupportedRelation('The given information to build a many-to-many-relation was not sufficient. Check your TCA definitions. mm-relations with IRRE must have at least a defined "MM" or "foreign_selector".', 1268817963);
+               }
+               return $columnMap;
+       }
+               
+}
\ No newline at end of file
index cd03fe3..f08f87a 100644 (file)
@@ -66,6 +66,11 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        protected $dataMaps = array();
 
        /**
+        * @var Tx_Extbase_Persistence_Mapper_DataMapFactory
+        */
+       protected $dataMapFactory;
+       
+       /**
         * @var Tx_Extbase_Persistence_QueryFactoryInterface
         */
        protected $queryFactory;
@@ -83,6 +88,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         */
        public function __construct() {
                $this->queryFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory');
+               $this->dataMapFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_Mapper_DataMapFactory');
        }
 
        /**
@@ -192,44 +198,62 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
                } else {
                        $object->_setProperty('uid', $row['uid']);
                }
-               unset($properties['uid']);
                foreach ($properties as $propertyName => $propertyValue) {
                        if (!$dataMap->isPersistableProperty($propertyName)) continue;
                        $columnMap = $dataMap->getColumnMap($propertyName);
                        $columnName = $columnMap->getColumnName();
+                       $propertyData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);                       
                        $propertyValue = NULL;
-                       
-                       $propertyMetaData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);
-                       $propertyType = Tx_Extbase_Persistence_PropertyType::valueFromType($propertyMetaData['type']);
-
-                       if ($propertyType == Tx_Extbase_Persistence_PropertyType::UNDEFINED) {
-                               $propertyType = $columnMap->getPropertyType();
-                       }
-
-                       switch ($propertyType) {
-                               case Tx_Extbase_Persistence_PropertyType::STRING;
-                               case Tx_Extbase_Persistence_PropertyType::DATE;
-                               case Tx_Extbase_Persistence_PropertyType::LONG;
-                               case Tx_Extbase_Persistence_PropertyType::DOUBLE;
-                               case Tx_Extbase_Persistence_PropertyType::BOOLEAN;
-                               if (isset($row[$columnName])) {
-                                       $rawPropertyValue = $row[$columnName];
-                                       $propertyValue = $dataMap->convertFieldValueToPropertyValue($propertyType, $rawPropertyValue);
-                               }
-                               break;
-                               case (Tx_Extbase_Persistence_PropertyType::REFERENCE):
-                                       $propertyValue = $row[$columnName];
-                                       if (!is_null($propertyValue)) {
-                                               $fieldValue = $row[$columnName];
-                                               $result = $this->fetchRelated($object, $propertyName, $fieldValue);
-                                               $propertyValue = $this->mapResultToPropertyValue($object, $propertyName, $result);
-                                       }
+                       if ($row[$columnName] !== NULL) {
+                               switch ($propertyData['type']) {
+                                       case 'integer':
+                                               $propertyValue = (int) $row[$columnName];
+                                       break;
+                                       case 'float':
+                                               $propertyValue = (float) $row[$columnName];
                                        break;
-                               default:
-                                       // FIXME throw exception
+                                       case 'boolean':
+                                               $propertyValue = (boolean) $row[$columnName];
                                        break;
+                                       case 'string':
+                                               $propertyValue = (string) $row[$columnName];
+                                       break;
+                                       case 'array':
+                                               // $propertyValue = $this->mapArray($row[$columnName]); // Not supported, yet!
+                                       break;
+                                       case 'SplObjectStorage':
+                                       case 'Tx_Extbase_Persistence_ObjectStorage':
+                                               $propertyValue = $this->mapResultToPropertyValue($object, $propertyName, $this->fetchRelated($object, $propertyName, $row[$columnName]));
+                                       break;
+                                       default:
+                                               if (($propertyData['type'] === 'DateTime') || in_array('DateTime', class_parents($propertyData['type']))) {
+                                                       $propertyValue = $this->mapDateTime($row[$columnName]);
+                                               } else {
+                                                       $propertyValue = $this->mapResultToPropertyValue($object, $propertyName, $this->fetchRelated($object, $propertyName, $row[$columnName]));
+                                                       // $propertyValue = $this->mapToObject($row[$columnName]); // Not supported, yet!
+                                               }
+                                       break;
+                               }
+                       }
+
+                       if ($propertyValue !== NULL) {
+                               $object->_setProperty($propertyName, $propertyValue);
                        }
-                       $object->_setProperty($propertyName, $propertyValue);
+               }
+       }
+       
+       /**
+        * Creates a DateTime from an unix timestamp. If the input is empty
+        * NULL is returned.
+        *
+        * @param integer $timestamp
+        * @return DateTime
+        */
+       protected function mapDateTime($timestamp) {
+               if (empty($timestamp)) { // 0 -> NULL !!!
+                       return NULL;
+               } else {
+                       return new DateTime(date('c', $timestamp));
                }
        }
 
@@ -246,8 +270,8 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        public function fetchRelated(Tx_Extbase_DomainObject_DomainObjectInterface $parentObject, $propertyName, $fieldValue = '', $enableLazyLoading = TRUE, $performLanguageOverlay = TRUE) {
                $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
                $propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
-               if ($enableLazyLoading === TRUE && ($propertyMetaData['lazy'] || ($columnMap->getLoadingStrategy() !== Tx_Extbase_Persistence_Mapper_ColumnMap::STRATEGY_EAGER))) {
-                       if (($propertyMetaData['type'] === 'Tx_Extbase_Persistence_ObjectStorage') || ($columnMap->getLoadingStrategy() === Tx_Extbase_Persistence_Mapper_ColumnMap::STRATEGY_LAZY_STORAGE)) {
+               if ($enableLazyLoading === TRUE && $propertyMetaData['lazy']) {
+                       if ($propertyMetaData['type'] === 'Tx_Extbase_Persistence_ObjectStorage') {
                                $result = t3lib_div::makeInstance('Tx_Extbase_Persistence_LazyObjectStorage', $parentObject, $propertyName, $fieldValue);                               
                        } else {
                                if (empty($fieldValue)) {
@@ -398,7 +422,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
                $query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
                return $query->count();
        }
-
+       
        /**
         * Delegates the call to the Data Map.
         * Returns TRUE if the property is persistable (configured in $TCA)
@@ -421,37 +445,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        public function getDataMap($className) {
                if (!is_string($className) || strlen($className) === 0) throw new Tx_Extbase_Persistence_Exception('No class name was given to retrieve the Data Map for.', 1251315965);
                if (!isset($this->dataMaps[$className])) {
-                       // FIXME This is too expensive for table name aliases -> implement a DataMapBuilder (knowing the aliases defined in $TCA)
-                       $columnMapping = array();
-                       $tableName = '';
-                       $extbaseSettings = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
-                       if (is_array($extbaseSettings['persistence']['classes'][$className])) {
-                               $persistenceSettings = $extbaseSettings['persistence']['classes'][$className];
-                               if (is_string($persistenceSettings['mapping']['tableName']) && strlen($persistenceSettings['mapping']['tableName']) > 0) {
-                                       $tableName = $persistenceSettings['mapping']['tableName'];
-                               }
-                               if (is_array($persistenceSettings['mapping']['columns'])) {
-                                       $columnMapping = $persistenceSettings['mapping']['columns'];
-                               }
-                       } elseif (class_exists($className)) {
-                               foreach (class_parents($className) as $parentClassName) {
-                                       $persistenceSettings = $extbaseSettings['persistence']['classes'][$parentClassName];
-                                       if (is_array($persistenceSettings)) {
-                                               if (is_string($persistenceSettings['mapping']['tableName']) && strlen($persistenceSettings['mapping']['tableName']) > 0) {
-                                                       $tableName = $persistenceSettings['mapping']['tableName'];
-                                               }
-                                               if (is_array($persistenceSettings['mapping']['columns'])) {
-                                                       $columnMapping = $persistenceSettings['mapping']['columns'];
-                                               }
-                                       }
-                                       break;
-                               }
-                       } else {
-                               throw new Tx_Extbase_Persistence_Exception('Could not determine a Data Map for given class name.', 1256067130);
-                       }
-
-                       $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap($className, $tableName, $columnMapping);
-                       $this->dataMaps[$className] = $dataMap;
+                       $this->dataMaps[$className] = $this->dataMapFactory->buildDataMap($className);
                }
                return $this->dataMaps[$className];
        }
@@ -463,10 +457,12 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         * @return string The selector name
         */
        public function convertClassNameToTableName($className = NULL) {
-               if (!empty($className)) {
-                       return $this->getDataMap($className)->getTableName();
+               if ($className !== NULL) {
+                       $tableName = $this->getDataMap($className)->getTableName();
+               } else {
+                       $tableName = strtolower($className);
                }
-               return strtolower($className);
+               return $tableName;
        }
 
        /**
@@ -501,7 +497,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
                if (!empty($propertyMetaData['type'])) {
                        $type = $propertyMetaData['type'];
                } else {
-                       throw new Tx_Extbase_Persistence_Exception_UnexpectedTypeException('Could not determine the child object object type.', 1251315967);
+                       throw new Tx_Extbase_Persistence_Exception_UnexpectedTypeException('Could not determine the child object type.', 1251315967);
                }
                return $type;
        }
index 9abf2b2..272b426 100644 (file)
@@ -329,7 +329,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                                        $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() . ' IS NULL';
                                } else {
                                        $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() . '=?';
-                                       $parameters[] = $dataMap->convertPropertyValueToFieldValue($propertyValue);
+                                       $parameters[] = $this->getPlainValue($propertyValue);
                                }
                        }
                }
index 9ea226f..049af58 100644 (file)
@@ -91,7 +91,9 @@ class Tx_Extbase_Reflection_ObjectAccess {
        static public function getPropertyPath($subject, $propertyPath) {
                $propertyPathSegments = explode('.', $propertyPath);
                foreach ($propertyPathSegments as $pathSegment) {
-                       if (is_array($subject) || (is_object($subject) && self::isPropertyGettable($subject, $pathSegment))) {
+                       if (is_object($subject) && self::isPropertyGettable($subject, $pathSegment)) {
+                               $subject = self::getProperty($subject, $pathSegment);
+                       } elseif (is_array($subject) && array_key_exists($pathSegment, $subject)) {
                                $subject = self::getProperty($subject, $pathSegment);
                        } else {
                                return NULL;
diff --git a/typo3/sysext/extbase/Tests/Persistence/Mapper/DataMapFactory_testcase.php b/typo3/sysext/extbase/Tests/Persistence/Mapper/DataMapFactory_testcase.php
new file mode 100644 (file)
index 0000000..f4571db
--- /dev/null
@@ -0,0 +1,285 @@
+<?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!
+***************************************************************/
+
+require_once(PATH_tslib . 'class.tslib_content.php');
+
+class Tx_Extbase_Persistence_Mapper_DataMapFactory_testcase extends Tx_Extbase_BaseTestCase {
+                       
+       /**
+        * @test
+        */
+       public function setRelationsDetectsOneToOneRelationOfTypeSelect() {
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+           $columnConfiguration = array(
+                       'type' => 'select',
+                       'foreign_table' => 'tx_myextension_bar',
+                       'foreign_field' => 'parentid',
+                       'foreign_table_field' => 'parenttable',
+                       'maxitems' => '1'
+                       );
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
+               $mockDataMap->expects($this->once())->method('setOneToOneRelation');
+               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
+               $mockDataMap->expects($this->never())->method('setManyToManyRelation');
+               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
+       }
+       
+       /**
+        * @test
+        */
+       public function setRelationsDetectsOneToOneRelationOfTypeInline() {
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+           $columnConfiguration = array(
+                       'type' => 'inline',
+                       'foreign_table' => 'tx_myextension_bar',
+                       'foreign_field' => 'parentid',
+                       'foreign_table_field' => 'parenttable',
+                       'maxitems' => '1'
+                       );
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
+               $mockDataMap->expects($this->once())->method('setOneToOneRelation');
+               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
+               $mockDataMap->expects($this->never())->method('setManyToManyRelation');
+               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
+       }
+       
+       /**
+        * @test
+        */
+       public function setRelationsDetectsOneToManyRelationOfTypeSelect() {
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+           $columnConfiguration = array(
+                       'type' => 'select',
+                       'foreign_table' => 'tx_myextension_bar',
+                       'foreign_field' => 'parentid',
+                       'foreign_table_field' => 'parenttable'
+                       );
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
+               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
+               $mockDataMap->expects($this->once())->method('setOneToManyRelation');
+               $mockDataMap->expects($this->never())->method('setManyToManyRelation');
+               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
+       }
+       
+       /**
+        * @test
+        */
+       public function setRelationsDetectsOneToManyRelationWitTypeInline() {
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+           $columnConfiguration = array(
+                       'type' => 'inline',
+                       'foreign_table' => 'tx_myextension_bar',
+                       'foreign_field' => 'parentid',
+                       'foreign_table_field' => 'parenttable'
+                       );
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
+               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
+               $mockDataMap->expects($this->once())->method('setOneToManyRelation');
+               $mockDataMap->expects($this->never())->method('setManyToManyRelation');
+               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
+       }
+
+       /**
+        * @test
+        */
+       public function setRelationsDetectsManyToManyRelationOfTypeSelect() {
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+           $columnConfiguration = array(
+                       'type' => 'select',
+                       'foreign_table' => 'tx_myextension_bar',
+                       'MM' => 'tx_myextension_mm'
+                       );
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
+               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
+               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
+               $mockDataMap->expects($this->once())->method('setManyToManyRelation');
+               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
+       }
+       
+       /**
+        * @test
+        */
+       public function setRelationsDetectsManyToManyRelationOfTypeInlineWithIntermediateTable() {
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+           $columnConfiguration = array(
+                       'type' => 'inline',
+                       'foreign_table' => 'tx_myextension_righttable',
+                       'MM' => 'tx_myextension_mm'
+                       );
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
+               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
+               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
+               $mockDataMap->expects($this->once())->method('setManyToManyRelation');
+               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
+       }
+       
+       /**
+        * @test
+        */
+       public function setRelationsDetectsManyToManyRelationOfTypeInlineWithForeignSelector() {
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+           $columnConfiguration = array(
+                       'type' => 'inline',
+                       'foreign_table' => 'tx_myextension_mm',
+                       'foreign_field' => 'uid_local',
+                       'foreign_selector' => 'uid_foreign'
+                       );
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
+               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
+               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
+               $mockDataMap->expects($this->once())->method('setManyToManyRelation');
+               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
+       }
+       
+       /**
+        * @test
+        */
+       public function columnMapIsInitializedWithManyToManyRelationOfTypeSelect() {
+               $leftColumnsDefinition = array(
+                       'rights' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_myextension_righttable',
+                               'foreign_table_where' => 'WHERE 1=1',
+                               'MM' => 'tx_myextension_mm',
+                               'MM_table_where' => 'WHERE 2=2',
+                               ),
+                       );
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+               $mockColumnMap->expects($this->once())->method('setTypeOfRelation')->with($this->equalTo(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY));
+               $mockColumnMap->expects($this->once())->method('setChildTableName')->with($this->equalTo('tx_myextension_righttable'));
+               $mockColumnMap->expects($this->once())->method('setChildTableWhereStatement')->with($this->equalTo('WHERE 1=1'));
+               $mockColumnMap->expects($this->once())->method('setChildSortbyFieldName')->with($this->equalTo('sorting'));
+               $mockColumnMap->expects($this->once())->method('setParentKeyFieldName')->with($this->equalTo('uid_local'));
+               $mockColumnMap->expects($this->never())->method('setParentTableFieldName');
+               $mockColumnMap->expects($this->never())->method('setRelationTableMatchFields');
+               $mockColumnMap->expects($this->never())->method('setRelationTableInsertFields');
+               
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('dummy'), array(), '', FALSE);
+               $mockDataMap->_callRef('setManyToManyRelation', $mockColumnMap, $leftColumnsDefinition['rights']);
+       }
+       
+       /**
+        * @test
+        */
+       public function columnMapIsInitializedWithOppositeManyToManyRelationOfTypeSelect() {
+               $rightColumnsDefinition = array(
+                       'lefts' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_myextension_lefttable',
+                               'MM' => 'tx_myextension_mm',
+                               'MM_opposite_field' => 'rights'
+                               ),
+                       );
+               $leftColumnsDefinition['rights']['MM_opposite_field'] = 'opposite_field';               
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+               $mockColumnMap->expects($this->once())->method('setTypeOfRelation')->with($this->equalTo(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY));
+               $mockColumnMap->expects($this->once())->method('setChildTableName')->with($this->equalTo('tx_myextension_lefttable'));
+               $mockColumnMap->expects($this->once())->method('setChildTableWhereStatement')->with(NULL);
+               $mockColumnMap->expects($this->once())->method('setChildSortbyFieldName')->with($this->equalTo('sorting_foreign'));
+               $mockColumnMap->expects($this->once())->method('setParentKeyFieldName')->with($this->equalTo('uid_foreign'));
+               $mockColumnMap->expects($this->never())->method('setParentTableFieldName');
+               $mockColumnMap->expects($this->never())->method('setRelationTableMatchFields');
+               $mockColumnMap->expects($this->never())->method('setRelationTableInsertFields');
+               
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('dummy'), array(), '', FALSE);
+               $mockDataMap->_callRef('setManyToManyRelation', $mockColumnMap, $rightColumnsDefinition['lefts']);
+       }
+       
+       /**
+        * @test
+        */
+       public function columnMapIsInitializedWithManyToManyRelationOfTypeInlineAndIntermediateTable() {
+           $leftColumnsDefinition = array(
+                       'rights' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_myextension_righttable',
+                               'MM' => 'tx_myextension_mm',
+                               'foreign_sortby' => 'sorting'
+                               )
+                       );
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+               $mockColumnMap->expects($this->once())->method('setTypeOfRelation')->with($this->equalTo(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY));
+               $mockColumnMap->expects($this->once())->method('setChildTableName')->with($this->equalTo('tx_myextension_righttable'));
+               $mockColumnMap->expects($this->once())->method('setChildTableWhereStatement');
+               $mockColumnMap->expects($this->once())->method('setChildSortbyFieldName')->with($this->equalTo('sorting'));
+               $mockColumnMap->expects($this->once())->method('setParentKeyFieldName')->with($this->equalTo('uid_local'));
+               $mockColumnMap->expects($this->never())->method('setParentTableFieldName');
+               $mockColumnMap->expects($this->never())->method('setRelationTableMatchFields');
+               $mockColumnMap->expects($this->never())->method('setRelationTableInsertFields');
+               
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('getColumnsDefinition'), array(), '', FALSE);
+               $mockDataMap->expects($this->never())->method('getColumnsDefinition');
+               $mockDataMap->_callRef('setManyToManyRelation', $mockColumnMap, $leftColumnsDefinition['rights']);
+       }
+
+       /**
+        * @test
+        */
+       public function columnMapIsInitializedWithManyToManyRelationOfTypeInlineAndForeignSelector() {
+           $leftColumnsDefinition = array(
+                       'rights' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_myextension_mm',
+                               'foreign_field' => 'uid_local',
+                               'foreign_selector' => 'uid_foreign',
+                               'foreign_sortby' => 'sorting'
+                               )
+                       );
+           $relationTableColumnsDefiniton = array(
+                       'uid_local' => array(
+                               'config' => array('foreign_table' => 'tx_myextension_localtable')
+                               ),
+                       'uid_foreign' => array(
+                               'config' => array('foreign_table' => 'tx_myextension_righttable')
+                               )
+                       );
+           $rightColumnsDefinition = array(
+                       'lefts' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_myextension_mm',
+                               'foreign_field' => 'uid_foreign',
+                               'foreign_selector' => 'uid_local',
+                               'foreign_sortby' => 'sorting_foreign'
+                               )
+                       );
+               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
+               $mockColumnMap->expects($this->once())->method('setTypeOfRelation')->with($this->equalTo(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY));
+               $mockColumnMap->expects($this->once())->method('setChildTableName')->with($this->equalTo('tx_myextension_righttable'));
+               $mockColumnMap->expects($this->never())->method('setChildTableWhereStatement');
+               $mockColumnMap->expects($this->once())->method('setChildSortbyFieldName')->with($this->equalTo('sorting'));
+               $mockColumnMap->expects($this->once())->method('setParentKeyFieldName')->with($this->equalTo('uid_local'));
+               $mockColumnMap->expects($this->never())->method('setParentTableFieldName');
+               $mockColumnMap->expects($this->never())->method('setRelationTableMatchFields');
+               $mockColumnMap->expects($this->never())->method('setRelationTableInsertFields');
+               
+               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMapFactory'), array('getColumnsDefinition'), array(), '', FALSE);
+               $mockDataMap->expects($this->once())->method('getColumnsDefinition')->with($this->equalTo('tx_myextension_mm'))->will($this->returnValue($relationTableColumnsDefiniton));
+               $mockDataMap->_callRef('setManyToManyRelation', $mockColumnMap, $leftColumnsDefinition['rights']);
+       }
+       
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Persistence/Mapper/DataMap_testcase.php b/typo3/sysext/extbase/Tests/Persistence/Mapper/DataMap_testcase.php
deleted file mode 100644 (file)
index eb718a1..0000000
+++ /dev/null
@@ -1,440 +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!
-***************************************************************/
-
-require_once(PATH_tslib . 'class.tslib_content.php');
-
-class Tx_Extbase_Persistence_Mapper_DataMap_testcase extends Tx_Extbase_BaseTestCase {
-       
-       public function setUp() {
-               require_once(t3lib_extMgm::extPath('blog_example') . 'Classes/Domain/Model/Blog.php');
-       
-               $GLOBALS['TSFE']->fe_user = $this->getMock('tslib_feUserAuth');
-               $GLOBALS['TSFE'] = $this->getMock('tslib_fe', array('includeTCA'), array(), '', FALSE);
-               $this->setupTca();
-               $GLOBALS['TSFE']->expects($this->any())
-                       ->method('includeTCA')
-                       ->will($this->returnValue(NULL));
-               
-               
-               $GLOBALS['TSFE']->fe_user->user['uid'] = 999;
-               $GLOBALS['TSFE']->id = 42;
-       }
-       
-       public function setupTCA() {
-               global $TCA;
-               global $_EXTKEY;
-               $TCA['tx_blogexample_domain_model_blog'] = array (
-                       'ctrl' => array (
-                               'title'             => 'LLL:EXT:blog_example/Resources/Language/locallang_db.xml:tx_blogexample_domain_model_blog',
-                               'label'                         => 'name',
-                               'tstamp'            => 'tstamp',
-                               'prependAtCopy'     => 'LLL:EXT:lang/locallang_general.xml:LGL.prependAtCopy',
-                               'delete'            => 'deleted',
-                               'enablecolumns'     => array (
-                                       'disabled' => 'hidden'
-                               ),
-                               'iconfile'          => t3lib_extMgm::extRelPath($_EXTKEY).'Resources/Icons/icon_tx_blogexample_domain_model_blog.gif'
-                       ),
-                       'interface' => array(
-                               'showRecordFieldList' => 'hidden, name, description, logo, posts'
-                       ),
-                       'columns' => array(
-                               'hidden' => array(
-                                       'exclude' => 1,
-                                       'label'   => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
-                                       'config'  => array(
-                                               'type' => 'check'
-                                       )
-                               ),
-                               'name' => array(
-                                       'exclude' => 0,
-                                       'label'   => 'LLL:EXT:blog_example/Resources/Language/locallang_db.xml:tx_blogexample_domain_model_blog.name',
-                                       'config'  => array(
-                                               'type' => 'input',
-                                               'size' => 20,
-                                               'eval' => 'trim,required',
-                                               'max'  => 256
-                                       )
-                               ),
-                               'description' => array(
-                                       'exclude' => 1,
-                                       'label'   => 'LLL:EXT:blog_example/Resources/Language/locallang_db.xml:tx_blogexample_domain_model_blog.description',
-                                       'config'  => array(
-                                               'type' => 'text',
-                                               'eval' => 'required',
-                                               'rows' => 30,
-                                               'cols' => 80,
-                                       )
-                               ),
-                               'logo' => array(
-                                       'exclude' => 1,
-                                       'label'   => 'LLL:EXT:blog_example/Resources/Language/locallang_db.xml:tx_blogexample_domain_model_blog.logo',
-                                       'config'  => array(
-                                               'type'          => 'group',
-                                               'internal_type' => 'file',
-                                               'allowed'       => $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'],
-                                               'max_size'      => 3000,
-                                               'uploadfolder'  => 'uploads/pics',
-                                               'show_thumbs'   => 1,
-                                               'size'          => 1,
-                                               'maxitems'      => 1,
-                                               'minitems'      => 0
-                                       )
-                               ),
-                               'posts' => array(
-                                       'exclude' => 1,
-                                       'label'   => 'LLL:EXT:blog_example/Resources/Language/locallang_db.xml:tx_blogexample_domain_model_blog.posts',
-                                       'config' => array(
-                                               'type' => 'inline',
-                                               'foreign_class' => 'Tx_BlogExample_Domain_Model_Post',
-                                               'foreign_table' => 'tx_blogexample_domain_model_post',
-                                               'foreign_field' => 'blog',
-                                               'foreign_table_field' => 'blog_table',
-                                               'appearance' => array(
-                                                       'newRecordLinkPosition' => 'bottom',
-                                                       'collapseAll' => 1,
-                                                       'expandSingle' => 1,
-                                               ),
-                                       )
-                               ),
-                               'author' => array(
-                                       'exclude' => 1,
-                                       'label'   => 'LLL:EXT:blog_example/Resources/Language/locallang_db.xml:tx_blogexample_domain_model_blog.author',
-                                       'config' => array(
-                                               'type' => 'select',
-                                               'foreign_class' => 'Tx_BlogExample_Domain_Model_Author',
-                                               'foreign_table' => 'tx_blogexample_domain_model_author',
-                                               'maxitems' => 1,
-                                       )
-                               ),
-                       ),
-                       'types' => array(
-                               '1' => array('showitem' => 'hidden, name, description, logo, posts')
-                       ),
-                       'palettes' => array(
-                               '1' => array('showitem' => '')
-                       )
-               );
-       }
-
-       // public function test_DataMapCanBeInitialized() {
-       //      $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap('Tx_BlogExample_Domain_Model_Blog');
-       //      $columnMaps = $dataMap->getColumnMaps();
-       //      $this->assertEquals(10, count($columnMaps), 'The data map was not initialized (wrong number of column maps set).');
-       // }
-       // 
-       // public function test_DeletedColumnNameCanBeResolved() {
-       //      $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap('Tx_BlogExample_Domain_Model_Blog');
-       //      $deletedColumnName = $dataMap->getDeletedColumnName();
-       //      $this->assertEquals($deletedColumnName, 'deleted', 'The deleted column name could not be resolved.');
-       // }
-       // 
-       // public function test_HiddenColumnNameCanBeResolved() {
-       //      $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap('Tx_BlogExample_Domain_Model_Blog');
-       //      $hiddenColumnName = $dataMap->getHiddenColumnName();
-       //      $this->assertEquals($hiddenColumnName, 'hidden', 'The hidden column name could not be resolved.');
-       // }
-       // 
-       // public function test_ColumnCanBeAdded() {
-       //      $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap('Tx_BlogExample_Domain_Model_Blog');
-       //      $dataMap->addColumn('test_column');
-       //      $columnMaps = $dataMap->getColumnMaps();
-       //      $columnMap = array_pop($columnMaps);
-       //      $this->assertType('Tx_Extbase_Persistence_Mapper_ColumnMap', $columnMap, 'The column could not be added.');
-       // }
-       // 
-       // public function test_PersistablePropertyCanBeChecked() {
-       //      $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap('Tx_BlogExample_Domain_Model_Blog');
-       //      $dataMap->addColumn('configured_property');
-       //      $this->assertTrue($dataMap->isPersistableProperty('configuredProperty'), 'The persistable property was marked as unpersistable.');
-       //      $this->assertFalse($dataMap->isPersistableProperty('unconfiguredProperty'), 'The unpersistable property was marked asersistable.');
-       // }
-       // 
-       // public function test_HasManyColumnIsRegisteredForForeignTable() {
-       //      $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap('Tx_BlogExample_Domain_Model_Blog');
-       //      $this->assertEquals(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY, $dataMap->getColumnMap('posts')->getTypeOfRelation(), 'The posts relation was not of type HAS_MANY.');
-       // }
-       // 
-       // public function test_HasOneColumnIsRegisteredForForeignTableWithMaxsizeOne() {
-       //      $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap('Tx_BlogExample_Domain_Model_Blog');
-       //      $this->assertEquals(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE, $dataMap->getColumnMap('author')->getTypeOfRelation(), 'The author relation was not of type HAS_ONE.');
-       // }
-       
-       /**
-        * @test
-        */
-       public function setRelationsDetectsOneToOneRelationOfTypeSelect() {
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-           $columnConfiguration = array(
-                       'type' => 'select',
-                       'foreign_table' => 'tx_myextension_bar',
-                       'foreign_field' => 'parentid',
-                       'foreign_table_field' => 'parenttable',
-                       'maxitems' => '1'
-                       );
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
-               $mockDataMap->expects($this->once())->method('setOneToOneRelation');
-               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
-               $mockDataMap->expects($this->never())->method('setManyToManyRelation');
-               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
-       }
-       
-       /**
-        * @test
-        */
-       public function setRelationsDetectsOneToOneRelationOfTypeInline() {
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-           $columnConfiguration = array(
-                       'type' => 'inline',
-                       'foreign_table' => 'tx_myextension_bar',
-                       'foreign_field' => 'parentid',
-                       'foreign_table_field' => 'parenttable',
-                       'maxitems' => '1'
-                       );
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
-               $mockDataMap->expects($this->once())->method('setOneToOneRelation');
-               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
-               $mockDataMap->expects($this->never())->method('setManyToManyRelation');
-               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
-       }
-       
-       /**
-        * @test
-        */
-       public function setRelationsDetectsOneToManyRelationOfTypeSelect() {
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-           $columnConfiguration = array(
-                       'type' => 'select',
-                       'foreign_table' => 'tx_myextension_bar',
-                       'foreign_field' => 'parentid',
-                       'foreign_table_field' => 'parenttable'
-                       );
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
-               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
-               $mockDataMap->expects($this->once())->method('setOneToManyRelation');
-               $mockDataMap->expects($this->never())->method('setManyToManyRelation');
-               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
-       }
-       
-       /**
-        * @test
-        */
-       public function setRelationsDetectsOneToManyRelationWitTypeInline() {
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-           $columnConfiguration = array(
-                       'type' => 'inline',
-                       'foreign_table' => 'tx_myextension_bar',
-                       'foreign_field' => 'parentid',
-                       'foreign_table_field' => 'parenttable'
-                       );
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
-               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
-               $mockDataMap->expects($this->once())->method('setOneToManyRelation');
-               $mockDataMap->expects($this->never())->method('setManyToManyRelation');
-               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
-       }
-
-       /**
-        * @test
-        */
-       public function setRelationsDetectsManyToManyRelationOfTypeSelect() {
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-           $columnConfiguration = array(
-                       'type' => 'select',
-                       'foreign_table' => 'tx_myextension_bar',
-                       'MM' => 'tx_myextension_mm'
-                       );
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
-               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
-               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
-               $mockDataMap->expects($this->once())->method('setManyToManyRelation');
-               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
-       }
-       
-       /**
-        * @test
-        */
-       public function setRelationsDetectsManyToManyRelationOfTypeInlineWithIntermediateTable() {
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-           $columnConfiguration = array(
-                       'type' => 'inline',
-                       'foreign_table' => 'tx_myextension_righttable',
-                       'MM' => 'tx_myextension_mm'
-                       );
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
-               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
-               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
-               $mockDataMap->expects($this->once())->method('setManyToManyRelation');
-               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
-       }
-       
-       /**
-        * @test
-        */
-       public function setRelationsDetectsManyToManyRelationOfTypeInlineWithForeignSelector() {
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-           $columnConfiguration = array(
-                       'type' => 'inline',
-                       'foreign_table' => 'tx_myextension_mm',
-                       'foreign_field' => 'uid_local',
-                       'foreign_selector' => 'uid_foreign'
-                       );
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('setOneToOneRelation', 'setOneToManyRelation', 'setManyToManyRelation'), array(), '', FALSE);
-               $mockDataMap->expects($this->never())->method('setOneToOneRelation');
-               $mockDataMap->expects($this->never())->method('setOneToManyRelation');
-               $mockDataMap->expects($this->once())->method('setManyToManyRelation');
-               $mockDataMap->_callRef('setRelations', $mockColumnMap, $columnConfiguration);
-       }
-       
-       /**
-        * @test
-        */
-       public function columnMapIsInitializedWithManyToManyRelationOfTypeSelect() {
-               $leftColumnsDefinition = array(
-                       'rights' => array(
-                               'type' => 'select',
-                               'foreign_table' => 'tx_myextension_righttable',
-                               'foreign_table_where' => 'WHERE 1=1',
-                               'MM' => 'tx_myextension_mm',
-                               'MM_table_where' => 'WHERE 2=2',
-                               ),
-                       );
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-               $mockColumnMap->expects($this->once())->method('setTypeOfRelation')->with($this->equalTo(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY));
-               $mockColumnMap->expects($this->once())->method('setChildTableName')->with($this->equalTo('tx_myextension_righttable'));
-               $mockColumnMap->expects($this->once())->method('setChildTableWhereStatement')->with($this->equalTo('WHERE 1=1'));
-               $mockColumnMap->expects($this->once())->method('setChildSortbyFieldName')->with($this->equalTo('sorting'));
-               $mockColumnMap->expects($this->once())->method('setParentKeyFieldName')->with($this->equalTo('uid_local'));
-               $mockColumnMap->expects($this->never())->method('setParentTableFieldName');
-               $mockColumnMap->expects($this->never())->method('setRelationTableMatchFields');
-               $mockColumnMap->expects($this->never())->method('setRelationTableInsertFields');
-               
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('dummy'), array(), '', FALSE);
-               $mockDataMap->_callRef('setManyToManyRelation', $mockColumnMap, $leftColumnsDefinition['rights']);
-       }
-       
-       /**
-        * @test
-        */
-       public function columnMapIsInitializedWithOppositeManyToManyRelationOfTypeSelect() {
-               $rightColumnsDefinition = array(
-                       'lefts' => array(
-                               'type' => 'select',
-                               'foreign_table' => 'tx_myextension_lefttable',
-                               'MM' => 'tx_myextension_mm',
-                               'MM_opposite_field' => 'rights'
-                               ),
-                       );
-               $leftColumnsDefinition['rights']['MM_opposite_field'] = 'opposite_field';               
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-               $mockColumnMap->expects($this->once())->method('setTypeOfRelation')->with($this->equalTo(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY));
-               $mockColumnMap->expects($this->once())->method('setChildTableName')->with($this->equalTo('tx_myextension_lefttable'));
-               $mockColumnMap->expects($this->once())->method('setChildTableWhereStatement')->with(NULL);
-               $mockColumnMap->expects($this->once())->method('setChildSortbyFieldName')->with($this->equalTo('sorting_foreign'));
-               $mockColumnMap->expects($this->once())->method('setParentKeyFieldName')->with($this->equalTo('uid_foreign'));
-               $mockColumnMap->expects($this->never())->method('setParentTableFieldName');
-               $mockColumnMap->expects($this->never())->method('setRelationTableMatchFields');
-               $mockColumnMap->expects($this->never())->method('setRelationTableInsertFields');
-               
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('dummy'), array(), '', FALSE);
-               $mockDataMap->_callRef('setManyToManyRelation', $mockColumnMap, $rightColumnsDefinition['lefts']);
-       }
-       
-       /**
-        * @test
-        */
-       public function columnMapIsInitializedWithManyToManyRelationOfTypeInlineAndIntermediateTable() {
-           $leftColumnsDefinition = array(
-                       'rights' => array(
-                               'type' => 'inline',
-                               'foreign_table' => 'tx_myextension_righttable',
-                               'MM' => 'tx_myextension_mm',
-                               'foreign_sortby' => 'sorting'
-                               )
-                       );
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-               $mockColumnMap->expects($this->once())->method('setTypeOfRelation')->with($this->equalTo(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY));
-               $mockColumnMap->expects($this->once())->method('setChildTableName')->with($this->equalTo('tx_myextension_righttable'));
-               $mockColumnMap->expects($this->once())->method('setChildTableWhereStatement');
-               $mockColumnMap->expects($this->once())->method('setChildSortbyFieldName')->with($this->equalTo('sorting'));
-               $mockColumnMap->expects($this->once())->method('setParentKeyFieldName')->with($this->equalTo('uid_local'));
-               $mockColumnMap->expects($this->never())->method('setParentTableFieldName');
-               $mockColumnMap->expects($this->never())->method('setRelationTableMatchFields');
-               $mockColumnMap->expects($this->never())->method('setRelationTableInsertFields');
-               
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('getColumnsDefinition'), array(), '', FALSE);
-               $mockDataMap->expects($this->never())->method('getColumnsDefinition');
-               $mockDataMap->_callRef('setManyToManyRelation', $mockColumnMap, $leftColumnsDefinition['rights']);
-       }
-
-       /**
-        * @test
-        */
-       public function columnMapIsInitializedWithManyToManyRelationOfTypeInlineAndForeignSelector() {
-           $leftColumnsDefinition = array(
-                       'rights' => array(
-                               'type' => 'inline',
-                               'foreign_table' => 'tx_myextension_mm',
-                               'foreign_field' => 'uid_local',
-                               'foreign_selector' => 'uid_foreign',
-                               'foreign_sortby' => 'sorting'
-                               )
-                       );
-           $relationTableColumnsDefiniton = array(
-                       'uid_local' => array(
-                               'config' => array('foreign_table' => 'tx_myextension_localtable')
-                               ),
-                       'uid_foreign' => array(
-                               'config' => array('foreign_table' => 'tx_myextension_righttable')
-                               )
-                       );
-           $rightColumnsDefinition = array(
-                       'lefts' => array(
-                               'type' => 'inline',
-                               'foreign_table' => 'tx_myextension_mm',
-                               'foreign_field' => 'uid_foreign',
-                               'foreign_selector' => 'uid_local',
-                               'foreign_sortby' => 'sorting_foreign'
-                               )
-                       );
-               $mockColumnMap = $this->getMock('Tx_Extbase_Persistence_Mapper_ColumnMap', array(), array(), '', FALSE);
-               $mockColumnMap->expects($this->once())->method('setTypeOfRelation')->with($this->equalTo(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY));
-               $mockColumnMap->expects($this->once())->method('setChildTableName')->with($this->equalTo('tx_myextension_righttable'));
-               $mockColumnMap->expects($this->never())->method('setChildTableWhereStatement');
-               $mockColumnMap->expects($this->once())->method('setChildSortbyFieldName')->with($this->equalTo('sorting'));
-               $mockColumnMap->expects($this->once())->method('setParentKeyFieldName')->with($this->equalTo('uid_local'));
-               $mockColumnMap->expects($this->never())->method('setParentTableFieldName');
-               $mockColumnMap->expects($this->never())->method('setRelationTableMatchFields');
-               $mockColumnMap->expects($this->never())->method('setRelationTableInsertFields');
-               
-               $mockDataMap = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Mapper_DataMap'), array('getColumnsDefinition'), array(), '', FALSE);
-               $mockDataMap->expects($this->once())->method('getColumnsDefinition')->with($this->equalTo('tx_myextension_mm'))->will($this->returnValue($relationTableColumnsDefiniton));
-               $mockDataMap->_callRef('setManyToManyRelation', $mockColumnMap, $leftColumnsDefinition['rights']);
-       }
-       
-}
-?>
\ No newline at end of file