[+BUGFIX] Extbase (Persistence): The child class name is not determined by reverse...
authorJochen Rau <j.rau@web.de>
Mon, 15 Mar 2010 11:19:42 +0000 (11:19 +0000)
committerJochen Rau <j.rau@web.de>
Mon, 15 Mar 2010 11:19:42 +0000 (11:19 +0000)
[TASK] Extbase (Persistence): Changed signature of DataMapper::getType($class, $propertyName) to getType($className, $propertyName).
[+FEATURE] Extbase (Persistence): Property paths are now allowed as operand in orderings: $query->setOrderings(array('client.address.zip' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING));. Ordering across multi-value properties is not implemented, yet. Resolves #6825.
[TASK] Extbase (Persistence): The keyword DISTINCT is now added only if there are Joins.
[TASK] Extbase (Persistence): Refactored the parsing of Joins.

typo3/sysext/extbase/Classes/Persistence/Backend.php
typo3/sysext/extbase/Classes/Persistence/Mapper/ColumnMap.php
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMap.php
typo3/sysext/extbase/Classes/Persistence/Mapper/DataMapper.php
typo3/sysext/extbase/Classes/Persistence/QOM/Operand.php
typo3/sysext/extbase/Classes/Persistence/Query.php
typo3/sysext/extbase/Classes/Persistence/Storage/Typo3DbBackend.php

index 4bdcd42..aae8e41 100644 (file)
@@ -365,7 +365,6 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                        if (!$dataMap->isPersistableProperty($propertyName) || $this->propertyValueIsLazyLoaded($propertyValue)) continue;
                        
                        $columnMap = $dataMap->getColumnMap($propertyName);
-                       $childClassName = $columnMap->getChildClassName();
                        $propertyMetaData = $classSchema->getProperty($propertyName);
                        $propertyType = $propertyMetaData['type'];
                        // FIXME enable property-type check
@@ -435,6 +434,12 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                }
        }
        
+       /**
+        * Checks, if the property value is lazy loaded and was not initialized
+        *
+        * @param mixed $propertyValue The property value
+        * @return bool
+        */
        public function propertyValueIsLazyLoaded($propertyValue) {
                if ($propertyValue instanceof Tx_Extbase_Persistence_LazyLoadingProxy) return TRUE;
                if (is_object($propertyValue) && get_class($propertyValue) === 'Tx_Extbase_Persistence_LazyObjectStorage') {
index 1c8ec3d..f12d66f 100644 (file)
@@ -237,15 +237,7 @@ class Tx_Extbase_Persistence_Mapper_ColumnMap {
        public function getColumnName() {
                return $this->columnName;
        }
-
-       public function setChildClassName($childClassName) {
-               $this->childClassName = $childClassName;
-       }
-
-       public function getChildClassName() {
-               return $this->childClassName;
-       }
-
+       
        public function setChildTableName($childTableName) {
                $this->childTableName = $childTableName;
        }
index 579939d..d483d09 100644 (file)
@@ -213,13 +213,13 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         */
        protected function setRelations(Tx_Extbase_Persistence_Mapper_ColumnMap &$columnMap, $columnConfiguration) {
                if (isset($columnConfiguration) && $columnConfiguration['type'] !== 'passthrough') {
-                       if (isset($columnConfiguration['foreign_table']) && !isset($columnConfiguration['MM']) && !(isset($columnConfiguration['foreign_label']) || isset($columnConfiguration['foreign_selector']))) {
+                       if (isset($columnConfiguration['foreign_table']) && !isset($columnConfiguration['MM']) && !isset($columnConfiguration['foreign_selector'])) {
                                if ($columnConfiguration['maxitems'] == 1) {
                                        $this->setOneToOneRelation($columnMap, $columnConfiguration);
                                } else {
                                        $this->setOneToManyRelation($columnMap, $columnConfiguration);
                                }
-                       } elseif (isset($columnConfiguration['MM']) || (isset($columnConfiguration['foreign_label']) || isset($columnConfiguration['foreign_selector']))) {
+                       } elseif (isset($columnConfiguration['MM']) || isset($columnConfiguration['foreign_selector'])) {
                                $this->setManyToManyRelation($columnMap, $columnConfiguration);
                        } else {
                                $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_NONE);
@@ -237,7 +237,6 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         */
        protected function setOneToOneRelation(Tx_Extbase_Persistence_Mapper_ColumnMap &$columnMap, $columnConfiguration) {
                $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE);
-               $columnMap->setChildClassName($this->determineChildClassName($columnConfiguration));
                $columnMap->setChildTableName($columnConfiguration['foreign_table']);
                $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
                $columnMap->setChildSortbyFieldName($columnConfiguration['foreign_sortby']);
@@ -255,7 +254,6 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
         */
        protected function setOneToManyRelation(Tx_Extbase_Persistence_Mapper_ColumnMap &$columnMap, $columnConfiguration) {
                $columnMap->setTypeOfRelation(Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY);
-               $columnMap->setChildClassName($this->determineChildClassName($columnConfiguration));
                $columnMap->setChildTableName($columnConfiguration['foreign_table']);
                $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
                $columnMap->setChildSortbyFieldName($columnConfiguration['foreign_sortby']);
@@ -277,14 +275,12 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
                if ($columnConfiguration['type'] === 'inline') {
                        $columns = $this->getColumnsDefinition($columnConfiguration['foreign_table']);
                        $childKeyFieldName = $this->determineChildKeyFieldName($columnConfiguration);
-                       $columnMap->setChildClassName($this->determineChildClassName($columns[$childKeyFieldName]['config']));
                        $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 {
-                       $columnMap->setChildClassName($this->determineChildClassName($columnConfiguration));
                        $columnMap->setChildTableName($columnConfiguration['foreign_table']);
                        $columnMap->setChildTableWhereStatement($columnConfiguration['foreign_table_where']);
                        $columnMap->setRelationTableName($columnConfiguration['MM']);
@@ -326,34 +322,6 @@ class Tx_Extbase_Persistence_Mapper_DataMap {
        }
        
        /**
-        * This function determines the child class name. It can either be defined as foreign_class in the column configuration (TCA)
-        * or it must be defined in the extbase framework configuration (reverse mapping from tableName to className).
-        * 
-        * @param $columnConfiguration The column configuration (from TCA)
-        * @return string The class name of the related child object
-        */
-       protected function determineChildClassName($columnConfiguration) {
-               $foreignClassName = '';
-               if (is_string($columnConfiguration['foreign_class']) && (strlen($columnConfiguration['foreign_class']) > 0)) {
-                       $foreignClassName = $columnConfiguration['foreign_class'];
-               }
-               if (empty($foreignClassName)){
-                       $extbaseSettings = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
-                       // TODO Apply a cache to increase performance (profile first)
-                       if (is_array($extbaseSettings['persistence']['classes'])) {
-                               foreach ($extbaseSettings['persistence']['classes'] as $className => $classConfiguration) {
-                                       if ($classConfiguration['mapping']['tableName'] === $columnConfiguration['foreign_table']) {
-                                               $foreignClassName = $className;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               // TODO Throw exception if no appropriate class name was found
-               return $foreignClassName;
-       }
-
-       /**
         * Sets the column maps.
         *
         * @param array $columnMaps The column maps stored in a flat array.
index 934c78e..2007c64 100644 (file)
@@ -292,7 +292,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
                $parentKeyFieldName = $columnMap->getParentKeyFieldName();
                $childSortByFieldName = $columnMap->getChildSortByFieldName();
                if ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE) {
-                       $query = $queryFactory->create($this->getType($parentObject, $propertyName));
+                       $query = $queryFactory->create($this->getType(get_class($parentObject), $propertyName));
                        if (isset($parentKeyFieldName)) {
                                $query->matching($query->equals($parentKeyFieldName, $parentObject->getUid()));
                        } else {
@@ -331,7 +331,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
 
                        $query->setSource($source);
                        if (!empty($childSortByFieldName)) {
-                               $query->setOrderings(array($relationTableName . '.' . $childSortByFieldName => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING));
+                               $query->setOrderings(array($childSortByFieldName => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING));
                        }
                        
                        // attempt to support MM_match_fields
@@ -494,22 +494,18 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
        /**
         * Returns the type of a child object.
         *
-        * @param Tx_Extbase_DomainObject_DomainObjectInterface $parentObject The object instance this proxy is part of
+        * @param string $parentClassName The class name of the object 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_DomainObjectInterface $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'];
+       public function getType($parentClassName, $propertyName) {
+               $propertyMetaData = $this->reflectionService->getClassSchema($parentClassName)->getProperty($propertyName);
+               if (!empty($propertyMetaData['type'])) {
+                       $type = $propertyMetaData['type'];
                } else {
                        throw new Tx_Extbase_Persistence_Exception_UnexpectedTypeException('Could not determine the child object object type.', 1251315967);
                }
-               return $elementType;
+               return $type;
        }
 
        /**
@@ -521,11 +517,7 @@ class Tx_Extbase_Persistence_Mapper_DataMapper implements t3lib_Singleton {
         */
        public function getElementType($parentClassName, $propertyName) {
                $propertyMetaData = $this->reflectionService->getClassSchema($parentClassName)->getProperty($propertyName);
-               $columnMap = $this->getDataMap($parentClassName)->getColumnMap($propertyName);
-               $childClassName = $columnMap->getChildClassName();
-               if (!empty($childClassName)) {
-                       $elementType = $childClassName;
-               } elseif (!empty($propertyMetaData['elementType'])) {
+               if (!empty($propertyMetaData['elementType'])) {
                        $elementType = $propertyMetaData['elementType'];
                } else {
                        throw new Tx_Extbase_Persistence_Exception_UnexpectedTypeException('Could not determine the type of the contained objects.', 1251315966);
index e44e3fe..e8a8917 100644 (file)
  */
 class Tx_Extbase_Persistence_QOM_Operand implements Tx_Extbase_Persistence_QOM_OperandInterface {
 
-       /**
-        * Does nothing
-        *
-        * @param array &$boundVariables
-        * @return void
-        */
-       public function collectBoundVariableNames(&$boundVariables) {
-       }
-
 }
 
 ?>
\ No newline at end of file
index bc66d15..c294db3 100644 (file)
@@ -228,25 +228,15 @@ class Tx_Extbase_Persistence_Query implements Tx_Extbase_Persistence_QueryInterf
         * @api
         */
        public function setOrderings(array $orderings) {
-               $parsedOrderings = array();
-               foreach ($orderings as $propertyName => $order) {
-                       if ($order === Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING) {
-                               $parsedOrderings[] = $this->qomFactory->descending($this->qomFactory->propertyValue($propertyName));
-                       } elseif ($order === Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING) {
-                               $parsedOrderings[] = $this->qomFactory->ascending($this->qomFactory->propertyValue($propertyName));
-                       } else {
-                               throw new Tx_Extbase_Persistence_Exception_UnsupportedOrder('The order you specified for your query is not supported.', 1253785630);
-                       }
-               }
-               $this->orderings = $parsedOrderings;
+               $this->orderings = $orderings;
                return $this;
        }
        
        /**
         * Returns the property names to order the result by. Like this:
         * array(
-        *  'foo' => \F3\FLOW3\Persistence\QueryInterface::ORDER_ASCENDING,
-        *  'bar' => \F3\FLOW3\Persistence\QueryInterface::ORDER_DESCENDING
+        *  'foo' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING,
+        *  'bar' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
         * )
         *
         * @return array
index 8524e66..5496090 100644 (file)
@@ -227,8 +227,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                $this->checkSqlErrors();
                $rows = $this->getRowsFromResult($query->getSource(), $result);
                $rows = $this->doLanguageAndWorkspaceOverlay($query->getSource(), $rows);
-
-               // $objectData = $this->processObjectRecords($statementHandle);
+               // TODO: implement $objectData = $this->processObjectRecords($statementHandle);
                return $rows;
        }
 
@@ -261,6 +260,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         */
        public function parseQuery(Tx_Extbase_Persistence_QueryInterface $query, array &$parameters) {
                $sql = array();
+               $sql['keywords'] = array();
                $sql['tables'] = array();
                $sql['unions'] = array();
                $sql['fields'] = array();
@@ -293,7 +293,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         * @return string The SQL statement
         */
        public function buildQuery(array $sql) {
-               $statement = 'SELECT DISTINCT ' . implode(',', $sql['fields']) . ' FROM ' . implode(' ', $sql['tables']) . ' '. implode(' ', $sql['unions']);
+               $statement = 'SELECT ' . implode(' ', $sql['keywords']) . ' '. implode(',', $sql['fields']) . ' FROM ' . implode(' ', $sql['tables']) . ' '. implode(' ', $sql['unions']);
                if (!empty($sql['where'])) {
                        $statement .= ' WHERE ' . implode('', $sql['where']);
                        if (!empty($sql['additionalWhereClause'])) {
@@ -367,7 +367,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        protected function parseSource(Tx_Extbase_Persistence_QOM_SourceInterface $source, array &$sql) {
                if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
                        $tableName = $source->getSelectorName();
-                       $sql['fields'][] = $tableName . '.*';
+                       $sql['fields'][$tableName] = $tableName . '.*';
                        $sql['tables'][$tableName] = $tableName;
                } elseif ($source instanceof Tx_Extbase_Persistence_QOM_JoinInterface) {
                        $this->parseJoin($source, $sql);
@@ -383,26 +383,31 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         */
        protected function parseJoin(Tx_Extbase_Persistence_QOM_JoinInterface $join, array &$sql) {
                $leftSource = $join->getLeft();
+               $leftClassName = $leftSource->getNodeTypeName();
                $leftTableName = $leftSource->getSelectorName();
+               // $sql['fields'][$leftTableName] = $leftTableName . '.*';
                $rightSource = $join->getRight();
-               $rightTableName = $rightSource->getSelectorName();
-
-               $sql['fields'][] = $leftTableName . '.*';
-               $sql['fields'][] = $rightTableName . '.*';
-
-               // TODO Implement support for different join types and nested joins
+               if ($rightSource instanceof     Tx_Extbase_Persistence_QOM_JoinInterface) {
+                       $rightClassName = $rightSource->getLeft()->getNodeTypeName();
+                       $rightTableName = $rightSource->getLeft()->getSelectorName();
+               } else {
+                       $rightClassName = $rightSource->getNodeTypeName();
+                       $rightTableName = $rightSource->getSelectorName();
+                       $sql['fields'][$leftTableName] = $rightTableName . '.*';
+               }
+               
                $sql['tables'][$leftTableName] = $leftTableName;
-               $sql['unions'][$rightTableName] = 'LEFT JOIN ' . $rightTableName;
+               $sql['unions'][$rightTableName] = 'INNER JOIN ' . $rightTableName;
 
                $joinCondition = $join->getJoinCondition();
-               // TODO Check the parsing of the join
                if ($joinCondition instanceof Tx_Extbase_Persistence_QOM_EquiJoinCondition) {
-                       // TODO Discuss, if we should use $leftSource instead of $selector1Name
-                       $column1Name = $this->dataMapper->convertPropertyNameToColumnName($joinCondition->getProperty1Name(), $leftSource->getNodeTypeName());
-                       $column2Name = $this->dataMapper->convertPropertyNameToColumnName($joinCondition->getProperty2Name(), $rightSource->getNodeTypeName());
-                       $sql['unions'][$joinCondition->getSelector2Name()] .= ' ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
+                       $column1Name = $this->dataMapper->convertPropertyNameToColumnName($joinCondition->getProperty1Name(), $leftClassName);
+                       $column2Name = $this->dataMapper->convertPropertyNameToColumnName($joinCondition->getProperty2Name(), $rightClassName);
+                       $sql['unions'][$rightTableName] .= ' ON ' . $joinCondition->getSelector1Name() . '.' . $column1Name . ' = ' . $joinCondition->getSelector2Name() . '.' . $column2Name;
+               }
+               if ($rightSource instanceof Tx_Extbase_Persistence_QOM_JoinInterface) {
+                       $this->parseJoin($rightSource, $sql);
                }
-               // TODO Implement childtableWhere
        }
 
        /**
@@ -481,11 +486,11 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                                $sql['where'][] = '1<>1';
                        } else {
                                $className = $source->getNodeTypeName();
+                               $tableName = $this->dataMapper->convertClassNameToTableName($className);
                                $propertyName = $operand1->getPropertyName();
                                while (strpos($propertyName, '.') !== FALSE) {
-                                       $this->addUnionStatement($className, $propertyName, $sql);
+                                       $this->addUnionStatement($className, $tableName, $propertyName, $sql);
                                }
-                               $tableName = $this->dataMapper->convertClassNameToTableName($className);
                                $columnName = $this->dataMapper->convertPropertyNameToColumnName($propertyName, $className);
                                $dataMap = $this->dataMapper->getDataMap($className);
                                $columnMap = $dataMap->getColumnMap($propertyName);
@@ -518,7 +523,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                                }
                        }
                        $this->parseDynamicOperand($operand1, $operator, $source, $sql, $parameters);
-                       $parameters[] = $this->getPlainValue($operand2);                        
+                       $parameters[] = $this->getPlainValue($operand2);
                }
        }
        
@@ -557,14 +562,16 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                } elseif ($operand instanceof Tx_Extbase_Persistence_QOM_UpperCaseInterface) {
                        $this->parseDynamicOperand($operand->getOperand(), $operator, $source, $sql, $parameters, 'UPPER');
                } elseif ($operand instanceof Tx_Extbase_Persistence_QOM_PropertyValueInterface) {
+                       $propertyName = $operand->getPropertyName();
                        if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) { // FIXME Only necessary to differ from  Join
                                $className = $source->getNodeTypeName();
+                               $tableName = $this->dataMapper->convertClassNameToTableName($className);
+                               while (strpos($propertyName, '.') !== FALSE) {
+                                       $this->addUnionStatement($className, $tableName, $propertyName, $sql);
+                               }
+                       } elseif ($source instanceof Tx_Extbase_Persistence_QOM_JoinInterface) {
+                               $tableName = $source->getJoinCondition()->getSelector1Name();
                        }
-                       $propertyName = $operand->getPropertyName();
-                       while (strpos($propertyName, '.') !== FALSE) {
-                               $this->addUnionStatement($className, $propertyName, $sql);
-                       }
-                       $tableName = $this->dataMapper->convertClassNameToTableName($className);
                        $columnName = $this->dataMapper->convertPropertyNameToColumnName($propertyName, $className);
                        $operator = $this->resolveOperator($operator);
                        if ($valueFunction === NULL) {
@@ -577,7 +584,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                }
        }
        
-       protected function addUnionStatement(&$className, &$propertyPath, array &$sql) {
+       protected function addUnionStatement(&$className, &$tableName, &$propertyPath, array &$sql) {
                $explodedPropertyPath = explode('.', $propertyPath, 2);
                $propertyName = $explodedPropertyPath[0];
                $columnName = $this->dataMapper->convertPropertyNameToColumnName($propertyName, $className);
@@ -591,7 +598,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                        } else {
                                $sql['unions'][$childTableName] = 'INNER JOIN ' . $childTableName . ' ON ' . $tableName . '.' . $columnName . '=' . $childTableName . '.uid';
                        }
-                       $className = $columnMap->getChildClassName();
+                       $className = $this->dataMapper->getType($className, $propertyName);
                } elseif ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
                        if (isset($parentKeyFieldName)) {
                                $sql['unions'][$childTableName] = 'INNER JOIN ' . $childTableName . ' ON ' . $tableName . '.uid=' . $childTableName . '.' . $parentKeyFieldName;
@@ -610,7 +617,10 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                } else {
                        throw new Tx_Extbase_Persistence_Exception('Could not determine type of relation.', 1252502725);
                }
+               // TODO check if there is another solution for this
+               $sql['keywords']['distinct'] = 'DISTINCT';
                $propertyPath = $explodedPropertyPath[1];
+               $tableName = $childTableName;
        }
 
        /**
@@ -769,37 +779,27 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        /**
         * Transforms orderings into SQL.
         *
-        * @param array $orderings Ann array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
+        * @param array $orderings An array of orderings (Tx_Extbase_Persistence_QOM_Ordering)
         * @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source
         * @param array &$sql The query parts
         * @return void
         */
        protected function parseOrderings(array $orderings, Tx_Extbase_Persistence_QOM_SourceInterface $source, array &$sql) {
-               foreach ($orderings as $ordering) {
-                       $operand = $ordering->getOperand();
-                       $order = $ordering->getOrder();
-                       if ($operand instanceof Tx_Extbase_Persistence_QOM_PropertyValue) {
-                               switch ($order) {
-                                       case Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_ORDER_ASCENDING:
-                                               $order = 'ASC';
-                                               break;
-                                       case Tx_Extbase_Persistence_QOM_QueryObjectModelConstantsInterface::JCR_ORDER_DESCENDING:
-                                               $order = 'DESC';
-                                               break;
-                                       default:
-                                               throw new Tx_Extbase_Persistence_Exception_UnsupportedOrder('Unsupported order encountered.', 1242816074);
-                               }
-                               $tableName = $operand->getSelectorName();
-                               $className = '';
-                               if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
-                                       $className = $source->getNodeTypeName();
-                               }
-                               $columnName = $this->dataMapper->convertPropertyNameToColumnName($operand->getPropertyName(), $className);
-                               if (strlen($tableName) > 0) {
-                                       $sql['orderings'][] = $tableName . '.' . $columnName . ' ' . $order;
-                               } else {
-                                       $sql['orderings'][] = $columnName . ' ' . $order;
+               foreach ($orderings as $propertyName => $order) {
+                       if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
+                               $className = $source->getNodeTypeName();
+                               $tableName = $this->dataMapper->convertClassNameToTableName($className);
+                               while (strpos($propertyName, '.') !== FALSE) {
+                                       $this->addUnionStatement($className, $tableName, $propertyName, $sql);
                                }
+                       } elseif ($source instanceof Tx_Extbase_Persistence_QOM_JoinInterface) {
+                               $tableName = $source->getLeft()->getSelectorName();
+                       }
+                       $columnName = $this->dataMapper->convertPropertyNameToColumnName($propertyName, $className);
+                       if (strlen($tableName) > 0) {
+                               $sql['orderings'][] = $tableName . '.' . $columnName . ' ' . $order;
+                       } else {
+                               $sql['orderings'][] = $columnName . ' ' . $order;
                        }
                }
        }