[+BUGFIX] Extbase (Persistence): Removed testing code accidentally committed to trunk...
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Mapper / DataMapper.php
index 77ea041..5ca4b3f 100644 (file)
@@ -1,32 +1,32 @@
 <?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!
-***************************************************************/
+ *  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 mapper to map database tables configured in $TCA on domain objects.
  *
  * @package Extbase
- * @subpackage extbase
+ * @subpackage Persistence\Mapper
  * @version $ID:$
  */
 class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
@@ -37,9 +37,19 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        protected $identityMap;
 
        /**
-        * @var Tx_Extbase_Persistence_ManagerInterface
+        * @var Tx_Extbase_Reflection_Service
+        */
+       protected $reflectionService;
+
+       /**
+        * @var Tx_Extbase_Persistence_QOM_QueryObjectModelFactory
+        */
+       protected $QomFactory;
+
+       /**
+        * @var Tx_Extbase_Persistence_Session
         */
-       protected $persistenceManager;
+       protected $persistenceSession;
 
        /**
         * A reference to the page select object providing methods to perform language and work space overlays
@@ -73,7 +83,6 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         */
        public function __construct() {
                $this->queryFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory');
-               $GLOBALS['TSFE']->includeTCA(); // TODO Move this to an appropriate position
        }
 
        /**
@@ -87,14 +96,33 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        }
 
        /**
-        * Injects the persistence manager
+        * Injects the persistence session
         *
-        * @param Tx_Extbase_Persistence_ManagerInterface $persistenceManager
+        * @param Tx_Extbase_Persistence_Session $persistenceSession
         * @return void
         */
-       public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
-               $this->persistenceManager = $persistenceManager;
-               $this->QOMFactory = $this->persistenceManager->getBackend()->getQOMFactory();
+       public function injectSession(Tx_Extbase_Persistence_Session $persistenceSession) {
+               $this->persistenceSession = $persistenceSession;
+       }
+
+       /**
+        * Injects the Reflection Service
+        *
+        * @param Tx_Extbase_Reflection_Service
+        * @return void
+        */
+       public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
+               $this->reflectionService = $reflectionService;
+       }
+       
+       /**
+        * Sets the query object model factory
+        *
+        * @param Tx_Extbase_Persistence_QOM_QueryObjectModelFactory $qomFactory
+        * @return void
+        */
+       public function setQomFactory(Tx_Extbase_Persistence_QOM_QueryObjectModelFactory $qomFactory) {
+               $this->qomFactory = $qomFactory;
        }
 
        /**
@@ -119,13 +147,14 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         * @return object
         */
        protected function mapSingleRow($className, Tx_Extbase_Persistence_RowInterface $row) {
-               if ($this->identityMap->hasUid($className, $row['uid'])) {
-                       $object = $this->identityMap->getObjectByUid($className, $row['uid']);
+               if ($this->identityMap->hasIdentifier($row->getValue('uid'), $className)) {
+                       $object = $this->identityMap->getObjectByIdentifier($row->getValue('uid'), $className);
                } else {
                        $object = $this->createEmptyObject($className);
                        $this->thawProperties($object, $row);
                        $this->identityMap->registerObject($object, $object->getUid());
                        $object->_memorizeCleanState();
+                       $this->persistenceSession->registerReconstitutedObject($object);
                }
                return $object;
        }
@@ -135,7 +164,6 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         *
         * @param string $className Name of the class to create a skeleton for
         * @return object The object skeleton
-        * @internal
         */
        protected function createEmptyObject($className) {
                // Note: The class_implements() function also invokes autoload to assure that the interfaces
@@ -156,102 +184,206 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
                $className = get_class($object);
                $dataMap = $this->getDataMap($className);
                $properties = $object->_getProperties();
-               $object->_setProperty('uid', $row['uid']);
+               $object->_setProperty('uid', $row->getValue('uid'));
                foreach ($properties as $propertyName => $propertyValue) {
                        if (!$dataMap->isPersistableProperty($propertyName)) continue;
                        $columnMap = $dataMap->getColumnMap($propertyName);
                        $columnName = $columnMap->getColumnName();
                        $propertyValue = NULL;
-                       $propertyType = $columnMap->getPropertyType();
+                       
+                       $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);
-                                       }
+                               if ($row->hasValue($columnName)) {
+                                       $rawPropertyValue = $row->getValue($columnName);
+                                       $propertyValue = $dataMap->convertFieldValueToPropertyValue($propertyType, $rawPropertyValue);
+                               }
                                break;
                                case (Tx_Extbase_Persistence_PropertyType::REFERENCE):
-                                       if (!is_null($row[$columnName])) {
-                                               $propertyValue = $this->mapRelatedObjects($object, $propertyName, $row, $columnMap);
-                                       } else {
-                                               $propertyValue = NULL;
+                                       $propertyValue = $row->getValue($columnName);
+                                       if (!is_null($propertyValue)) {
+                                               $fieldValue = $row->getValue($columnName);
+                                               $result = $this->fetchRelated($object, $propertyName, $fieldValue);
+                                               $propertyValue = $this->mapResultToPropertyValue($object, $propertyName, $result);
                                        }
-                               break;
-                                       // FIXME we have an object to handle... -> exception
+                                       break;
                                default:
-                                       // SK: We should throw an exception as this point as there was an undefined propertyType we can not handle.
-                                       if (isset($row[$columnName])) {
-                                               $property = $row[$columnName];
-                                               if (is_object($property)) {
-                                                       $propertyValue = $this->mapObject($property);
-                                                       // SK: THIS case can not happen I think. At least $this->mapObject() is not available.
-                                               } else {
-                                                       // SK: This case does not make sense either. $this-mapSingleRow has a different signature
-                                                       $propertyValue = $this->mapSingleRow($className, $property);
-                                               }
-                                       }
-                               break;
+                                       // FIXME throw exception
+                                       break;
                        }
-
                        $object->_setProperty($propertyName, $propertyValue);
                }
        }
 
        /**
-        * Maps related objects to an ObjectStorage
+        * Fetches a collection of objects related to a property of a parent object
         *
-        * @param object $parentObject The parent object for the mapping result
-        * @param string $propertyName The target property name for the mapping result
-        * @param Tx_Extbase_Persistence_RowInterface $row The actual database row
-        * @param int $loadingStrategy The loading strategy; one of Tx_Extbase_Persistence_Mapper_ColumnMap::STRATEGY_*
-        * @return array|Tx_Extbase_Persistence_ObjectStorage|Tx_Extbase_Persistence_LazyLoadingProxy|another implementation of a loading strategy
+        * @param Tx_Extbase_DomainObject_AbstractEntity $parentObject The object instance this proxy is part of
+        * @param string $propertyName The name of the proxied property in it's parent
+        * @param mixed $fieldValue The raw field value.
+        * @param Tx_Extbase_Persistence_Mapper_DataMap $dataMap The corresponding Data Map of the property
+        * @return mixed The result
         */
-       protected function mapRelatedObjects(Tx_Extbase_DomainObject_AbstractEntity $parentObject, $propertyName, Tx_Extbase_Persistence_RowInterface $row, Tx_Extbase_Persistence_Mapper_ColumnMap $columnMap) {
-               $dataMap = $this->getDataMap(get_class($parentObject));
-               $columnMap = $dataMap->getColumnMap($propertyName);
-               if ($columnMap->getLoadingStrategy() === Tx_Extbase_Persistence_Mapper_ColumnMap::STRATEGY_PROXY) {
-                       // TODO Remove dependency to the loading strategy implementation
-                       $result = t3lib_div::makeInstance('Tx_Extbase_Persistence_LazyLoadingProxy', $parentObject, $propertyName, $dataMap);
+       public function fetchRelated(Tx_Extbase_DomainObject_AbstractEntity $parentObject, $propertyName, $fieldValue = '', $enableLazyLoading = 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)) {
+                               $result = t3lib_div::makeInstance('Tx_Extbase_Persistence_LazyObjectStorage', $parentObject, $propertyName, $fieldValue);                               
+                       } else {
+                               $result = t3lib_div::makeInstance('Tx_Extbase_Persistence_LazyLoadingProxy', $parentObject, $propertyName, $fieldValue);
+                       }
                } else {
-                       if ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE) {
-                               $query = $this->queryFactory->create($columnMap->getChildClassName());
-                               $result = current($query->matching($query->withUid($row[$columnMap->getColumnName()]))->execute());
-                       } elseif ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
-                               $objectStorage = new Tx_Extbase_Persistence_ObjectStorage();
-                               $query = $this->queryFactory->create($columnMap->getChildClassName());
-                               $objects = $query->matching($query->equals($columnMap->getParentKeyFieldName(), $parentObject->getUid()))->execute();
-                               foreach ($objects as $object) {
-                                       $objectStorage->attach($object);
-                               }
-                               $result = $objectStorage;
-                       } elseif ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
-                               $objectStorage = new Tx_Extbase_Persistence_ObjectStorage();
-                               $relationTableName = $columnMap->getRelationTableName();
-                               $left = $this->QOMFactory->selector($relationTableName);
-                               $childTableName = $columnMap->getChildTableName();
-                               $right = $this->QOMFactory->selector($childTableName);
-                               $joinCondition = $this->QOMFactory->equiJoinCondition($relationTableName, 'uid_foreign', $childTableName, 'uid');
-                               $source = $this->QOMFactory->join(
-                                       $left,
-                                       $right,
-                                       Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_JOIN_TYPE_INNER,
-                                       $joinCondition
-                                       );
-                               $query = $this->queryFactory->create($columnMap->getChildClassName());
-                               $query->setSource($source);
-                               $objects = $query->matching($query->equals('uid_local', $parentObject->getUid()))->execute();
-                               foreach ($objects as $object) {
-                                       $objectStorage->attach($object);
+                       $result = $this->fetchRelatedEager($parentObject, $propertyName, $fieldValue);
+               }
+               return $result;
+       }
+       
+       /**
+        * Fetches the related objects from the storage backend.
+        *
+        * @param Tx_Extbase_DomainObject_AbstractEntity $parentObject The object instance this proxy is part of
+        * @param string $propertyName The name of the proxied property in it's parent
+        * @param mixed $fieldValue The raw field value.
+        * @return void
+        */
+       protected function fetchRelatedEager(Tx_Extbase_DomainObject_AbstractEntity $parentObject, $propertyName, $fieldValue = '') {
+               if ($fieldValue === '') return array();
+               $query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
+               return $query->execute();
+       }
+       
+       /**
+        * Builds and returns the prepared query, ready to be executed.
+        *
+        * @param Tx_Extbase_DomainObject_AbstractEntity $parentObject 
+        * @param string $propertyName 
+        * @param string $fieldValue 
+        * @return void
+        */
+       protected function getPreparedQuery(Tx_Extbase_DomainObject_AbstractEntity $parentObject, $propertyName, $fieldValue = '') {
+               $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
+               $queryFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryFactory');
+               $parentKeyFieldName = $columnMap->getParentKeyFieldName();
+               $childSortByFieldName = $columnMap->getChildSortByFieldName();
+               if ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE) {
+                       $query = $queryFactory->create($this->getType($parentObject, $propertyName));
+                       if (isset($parentKeyFieldName)) {
+                               $query->matching($query->equals($parentKeyFieldName, $parentObject->getUid()));
+                       } else {
+                               $query->matching($query->withUid(intval($fieldValue)));
+                       }
+               } elseif ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
+                       $query = $queryFactory->create($this->getElementType($parentObject, $propertyName));
+                       // TODO: This is an ugly hack, just ignoring the storage page state from here. Actually, the query settings would have to be passed into the DataMapper, so we can respect
+                       // enableFields and storage page settings.
+                       $query->getQuerySettings()->setRespectStoragePage(FALSE);
+                       if (!empty($childSortByFieldName)) {
+                               $query->setOrderings(array($childSortByFieldName => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING));
+                       }
+                       if (isset($parentKeyFieldName)) {
+                               $query->matching($query->equals($parentKeyFieldName, $parentObject->getUid()));
+                       } else {
+                               $query->matching($query->equals('uid', t3lib_div::intExplode(',', $fieldValue)));                                       
+                       }
+               } elseif ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
+                       $query = $queryFactory->create($this->getElementType($parentObject, $propertyName));
+                       // TODO: This is an ugly hack, just ignoring the storage page state from here. Actually, the query settings would have to be passed into the DataMapper, so we can respect
+                       // enableFields and storage page settings.
+                       $query->getQuerySettings()->setRespectStoragePage(FALSE);
+                       $relationTableName = $columnMap->getRelationTableName();
+                       $left = $this->qomFactory->selector(NULL, $relationTableName);
+                       $childClassName = $this->getElementType($parentObject, $propertyName);
+                       $childTableName = $columnMap->getChildTableName();
+                       $right = $this->qomFactory->selector($childClassName, $childTableName);
+                       $joinCondition = $this->qomFactory->equiJoinCondition($relationTableName, $columnMap->getChildKeyFieldName(), $childTableName, 'uid');
+                       $source = $this->qomFactory->join(
+                               $left,
+                               $right,
+                               Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_JOIN_TYPE_INNER,
+                               $joinCondition
+                               );
+
+                       $query->setSource($source);
+                       if (!empty($childSortByFieldName)) {
+                               $query->setOrderings(array($relationTableName . '.' . $childSortByFieldName => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING));
+                       }
+                       
+                       // attempt to support MM_match_fields
+                       $conditions = $query->equals($parentKeyFieldName, $parentObject->getUid());
+
+                       $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
+                       if (count($relationTableMatchFields)) {
+                               foreach($relationTableMatchFields as $relationTableMatchFieldName => $relationTableMatchFieldValue) {
+                                       $relationMatchCondition = $query->equals($relationTableName . '.' . $relationTableMatchFieldName, $relationTableMatchFieldValue);
+                                       $conditions = $query->logicalAnd($conditions, $relationMatchCondition);
                                }
-                               $result = $objectStorage;
                        }
+                       $query->matching($conditions);
+                       
+               } else {
+                       throw new Tx_Extbase_Persistence_Exception('Could not determine type of relation.', 1252502725);
                }
+               return $query;
+       }
 
-               return $result;
+       /**
+        * Returns the given result as property value of the specified property type.
+        *
+        * @param mixed $result The result could be an object or an ObjectStorage 
+        * @param array $propertyMetaData The property meta data
+        * @return void
+        */
+       public function mapResultToPropertyValue(Tx_Extbase_DomainObject_AbstractEntity $parentObject, $propertyName, $result) {
+               if ($result instanceof Tx_Extbase_Persistence_LoadingStrategyInterface) {
+                       $propertyValue = $result;
+               } else {
+                       $propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
+                       $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
+                       if (in_array($propertyMetaData['type'], array('array', 'ArrayObject', 'Tx_Extbase_Persistence_ObjectStorage'))) {
+                               $elementType = $this->getElementType($parentObject, $propertyName);
+                               $objects = array();
+                               foreach ($result as $value) {
+                                       $objects[] = $value;
+                               }
+
+                               if ($propertyMetaData['type'] === 'ArrayObject') {
+                                       $propertyValue = new ArrayObject($objects);
+                               } elseif ($propertyMetaData['type'] === 'Tx_Extbase_Persistence_ObjectStorage') {
+                                       $propertyValue = new Tx_Extbase_Persistence_ObjectStorage();
+                                       foreach ($objects as $object) {
+                                               $propertyValue->attach($object);
+                                       }
+                               } else {
+                                       $propertyValue = $objects;
+                               }
+                       } elseif (strpos($propertyMetaData['type'], '_') !== FALSE) {
+                               $propertyValue = current($result);
+                       }
+               }
+               return $propertyValue;
+       }
+       
+       /**
+        * Counts the number of related objects assigned to a property of a parent object
+        *
+        * @param Tx_Extbase_DomainObject_AbstractEntity $parentObject The object instance this proxy is part of
+        * @param string $propertyName The name of the proxied property in it's parent
+        * @param mixed $fieldValue The raw field value.
+        */
+       public function countRelated(Tx_Extbase_DomainObject_AbstractEntity $parentObject, $propertyName, $fieldValue = '') {
+               $query = $this->getPreparedQuery($parentObject, $propertyName, $fieldValue);
+               return $query->count();
        }
 
        /**
@@ -269,32 +401,46 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
 
        /**
         * Returns a data map for a given class name
-        *
+        * 
+        * @param string $className The class name you want to fetch the Data Map for
         * @return Tx_Extbase_Persistence_Mapper_DataMap The data map
         */
        public function getDataMap($className) {
-               global $TCA;
-               if (empty($this->dataMaps[$className])) {
-                       // FIXME This is a costy for table name aliases -> implement a DataMapBuilder (knowing the aliases defined in $TCA)
-                       $mapping = array();
-                       $extbaseSettings = Tx_Extbase_Dispatcher::getSettings();
-                       if (isset($extbaseSettings['classes'][$className]) && !empty($extbaseSettings['classes'][$className]['mapping']['tableName'])) {
-                               $tableName = $extbaseSettings['classes'][$className]['mapping']['tableName'];
-                       } else {
+               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) {
-                                       if (isset($extbaseSettings['classes'][$parentClassName]) && !empty($extbaseSettings['classes'][$parentClassName]['mapping']['tableName'])) {
-                                               $tableName = $extbaseSettings['classes'][$parentClassName]['mapping']['tableName'];
-                                               $mapping = $extbaseSettings['classes'][$parentClassName]['mapping']['columns'];
-                                               break;
+                                       $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'];
+                                               }
                                        }
-                                       // TODO throw Exception
+                                       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, $mapping);
+
+                       $dataMap = new Tx_Extbase_Persistence_Mapper_DataMap($className, $tableName, $columnMapping);
                        $this->dataMaps[$className] = $dataMap;
                }
-               return $this->dataMaps[$className];
+               return $this->dataMaps[$className];
        }
 
        /**
@@ -303,9 +449,71 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         * @param string $className
         * @return string The selector name
         */
-       public function convertClassNameToSelectorName($className) {
+       public function convertClassNameToTableName($className) {
                return $this->getDataMap($className)->getTableName();
        }
 
+       /**
+        * Returns the column name for a given property name of the specified class.
+        *
+        * @param string $className
+        * @param string $propertyName
+        * @return string The column name
+        */
+       public function convertPropertyNameToColumnName($propertyName, $className = '') {
+               if (!empty($className)) {
+                       $dataMap = $this->getDataMap($className);
+                       if ($dataMap !== NULL) {
+                               $columnMap = $dataMap->getColumnMap($propertyName);
+                               if ($columnMap !== NULL) {
+                                       return $columnMap->getColumnName();
+                               }
+                       }
+               }
+               return Tx_Extbase_Utility_Extension::convertCamelCaseToLowerCaseUnderscored($propertyName);
+       }
+       
+       /**
+        * Returns the type of a child object.
+        *
+        * @param Tx_Extbase_DomainObject_AbstractEntity $parentObject The object instance this proxy is part of
+        * @param string $propertyName The name of the proxied property in it's parent
+        * @return string The class name of the child object
+        */
+       protected function getType(Tx_Extbase_DomainObject_AbstractEntity $parentObject, $propertyName) {
+               $propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
+               $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
+               $childClassName = $columnMap->getChildClassName();
+               if (!empty($childClassName)) {
+                       $elementType = $childClassName;
+               } elseif (!empty($propertyMetaData['type'])) {
+                       $elementType = $propertyMetaData['type'];
+               } else {
+                       throw new Tx_Extbase_Persistence_Exception_UnexpectedTypeException('Could not determine the child object object type.', 1251315967);
+               }
+               return $elementType;
+       }
+
+       /**
+        * Returns the type of the elements inside an ObjectStorage or array.
+        *
+        * @param Tx_Extbase_DomainObject_AbstractEntity $parentObject The object instance this proxy is part of
+        * @param string $propertyName The name of the proxied property in it's parent
+        * @return string The class name of the elements inside an ObjectStorage
+        */
+       protected function getElementType(Tx_Extbase_DomainObject_AbstractEntity $parentObject, $propertyName) {
+               $propertyMetaData = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
+               $columnMap = $this->getDataMap(get_class($parentObject))->getColumnMap($propertyName);
+               $childClassName = $columnMap->getChildClassName();
+               if (!empty($childClassName)) {
+                       $elementType = $childClassName;
+               } elseif (!empty($propertyMetaData['elementType'])) {
+                       $elementType = $propertyMetaData['elementType'];
+               } else {
+                       throw new Tx_Extbase_Persistence_Exception_UnexpectedTypeException('Could not determine the type of the contained objects.', 1251315966);
+               }
+               return $elementType;            
+       }
+
 }
-?>
+?>
\ No newline at end of file