diff --git a/lib/Doctrine/Common/NotifyPropertyChanged.php b/lib/Doctrine/Common/NotifyPropertyChanged.php new file mode 100644 index 000000000..dbc8306d8 --- /dev/null +++ b/lib/Doctrine/Common/NotifyPropertyChanged.php @@ -0,0 +1,35 @@ +. + */ + +namespace Doctrine\Common; + +/** + * Contract for classes that provide the service of notifying listeners of + * changes to their properties. + * + * @author robo + * @since 2.0 + */ +interface NotifyPropertyChanged +{ + public function addPropertyChangedListener(PropertyChangedListener $listener); +} + diff --git a/lib/Doctrine/Common/PropertyChangedListener.php b/lib/Doctrine/Common/PropertyChangedListener.php new file mode 100644 index 000000000..fc27a09fc --- /dev/null +++ b/lib/Doctrine/Common/PropertyChangedListener.php @@ -0,0 +1,35 @@ +. + */ + +namespace Doctrine\Common; + +/** + * Contract for classes that are potential listeners of a NotifyPropertyChanged + * implementor. + * + * @author robo + * @since 2.0 + */ +interface PropertyChangedListener +{ + public function propertyChanged($sender, $propertyName, $oldValue, $newValue); +} + diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index 2afe80537..272ef3a2a 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -35,21 +35,8 @@ use \PDO; */ abstract class AbstractHydrator { - /** - * @var array $_queryComponents - * - * Two dimensional array containing the map for query aliases. Main keys are component aliases. - * - * metadata ClassMetadata object associated with given alias. - * relation Relation object owned by the parent. - * parent Alias of the parent. - * agg Aggregates of this component. - * map Name of the column / aggregate value this component is mapped to in a collection. - */ - protected $_queryComponents = array(); - - /** @var array Table alias map. Keys are SQL aliases and values DQL aliases. */ - protected $_tableAliases = array(); + /** The ResultSetMapping. */ + protected $_resultSetMapping; /** @var EntityManager The EntityManager instance. */ protected $_em; @@ -133,8 +120,7 @@ abstract class AbstractHydrator */ protected function _prepare($parserResult) { - $this->_queryComponents = $parserResult->getQueryComponents(); - $this->_tableAliases = $parserResult->getTableAliasMap(); + $this->_resultSetMapping = $parserResult->getResultSetMapping(); $this->_parserResult = $parserResult; } @@ -144,6 +130,7 @@ abstract class AbstractHydrator */ protected function _cleanup() { + $this->_resultSetMapping = null; $this->_parserResult = null; $this->_stmt->closeCursor(); $this->_stmt = null; @@ -159,7 +146,9 @@ abstract class AbstractHydrator * @param mixed $result The result to fill. */ protected function _hydrateRow(array &$data, array &$cache, &$result) - {} + { + throw new Exception("_hydrateRow() not implemented for this hydrator."); + } /** * Hydrates all rows from the current statement instance at once. @@ -193,24 +182,19 @@ abstract class AbstractHydrator if ( ! isset($cache[$key])) { if ($this->_isIgnoredName($key)) continue; - // Cache general information like the column name <-> field name mapping - $e = explode(\Doctrine\ORM\Query\SqlWalker::SQLALIAS_SEPARATOR, $key); - $columnName = array_pop($e); - $cache[$key]['dqlAlias'] = $this->_tableAliases[ - implode(\Doctrine\ORM\Query\SqlWalker::SQLALIAS_SEPARATOR, $e) - ]; - // check whether it's an aggregate value or a regular field - if ($cache[$key]['dqlAlias'] == 'dctrn') { - $cache[$key]['fieldName'] = $columnName; + if ($this->_resultSetMapping->isScalarResult($key)) { + $cache[$key]['fieldName'] = $this->_resultSetMapping->getScalarAlias($key); $cache[$key]['isScalar'] = true; } else { - $classMetadata = $this->_queryComponents[$cache[$key]['dqlAlias']]['metadata']; - $fieldName = $this->_lookupFieldName($classMetadata, $columnName); + $classMetadata = $this->_resultSetMapping->getOwningClass($key); + $fieldName = $this->_resultSetMapping->getFieldName($key); + $classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName); + //$fieldName = $classMetadata->getFieldNameForLowerColumnName($columnName); $cache[$key]['fieldName'] = $fieldName; $cache[$key]['isScalar'] = false; - $cache[$key]['type'] = $classMetadata->getTypeOfColumn($columnName); - // Cache identifier information + $cache[$key]['type'] = $classMetadata->getTypeOfField($fieldName); $cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName); + $cache[$key]['dqlAlias'] = $this->_resultSetMapping->getEntityAlias($key); } } @@ -261,31 +245,27 @@ abstract class AbstractHydrator if ( ! isset($cache[$key])) { if ($this->_isIgnoredName($key)) continue; - // cache general information like the column name <-> field name mapping - $e = explode(\Doctrine\ORM\Query\SqlWalker::SQLALIAS_SEPARATOR, $key); - $columnName = array_pop($e); - $sqlAlias = implode(\Doctrine\ORM\Query\SqlWalker::SQLALIAS_SEPARATOR, $e); - $cache[$key]['dqlAlias'] = $this->_tableAliases[$sqlAlias]; - // check whether it's a scalar value or a regular field - if ($cache[$key]['dqlAlias'] == 'dctrn') { - $cache[$key]['fieldName'] = $columnName; + if ($this->_resultSetMapping->isScalarResult($key)) { + $cache[$key]['fieldName'] = $this->_resultSetMapping->getScalarAlias($key); $cache[$key]['isScalar'] = true; } else { - $classMetadata = $this->_queryComponents[$cache[$key]['dqlAlias']]['metadata']; - $fieldName = $this->_lookupFieldName($classMetadata, $columnName); + $classMetadata = $this->_resultSetMapping->getOwningClass($key); + $fieldName = $this->_resultSetMapping->getFieldName($key); + $classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName); + //$fieldName = $classMetadata->getFieldNameForLowerColumnName($columnName); $cache[$key]['fieldName'] = $fieldName; $cache[$key]['isScalar'] = false; - // cache type information - $cache[$key]['type'] = $classMetadata->getTypeOfColumn($columnName); + $cache[$key]['type'] = $classMetadata->getTypeOfField($fieldName); + $cache[$key]['dqlAlias'] = $this->_resultSetMapping->getEntityAlias($key); } } - - $dqlAlias = $cache[$key]['dqlAlias']; + $fieldName = $cache[$key]['fieldName']; if ($cache[$key]['isScalar']) { - $rowData[$dqlAlias . '_' . $fieldName] = $value; + $rowData[/*$dqlAlias . '_' . */$fieldName] = $value; } else { + $dqlAlias = $cache[$key]['dqlAlias']; $rowData[$dqlAlias . '_' . $fieldName] = $cache[$key]['type']->convertToPHPValue($value); } } @@ -301,7 +281,8 @@ abstract class AbstractHydrator */ protected function _getCustomIndexField($alias) { - return isset($this->_queryComponents[$alias]['map']) ? $this->_queryComponents[$alias]['map'] : null; + return $this->_resultSetMapping->hasIndexBy($alias) ? + $this->_resultSetMapping->getIndexByField($alias) : null; } /** @@ -335,20 +316,21 @@ abstract class AbstractHydrator * @return string The field name. * @throws DoctrineException If the field name could not be found. */ - private function _lookupFieldName($class, $lcColumnName) + private function _lookupDeclaringClass($class, $fieldName) { - if ($class->hasLowerColumn($lcColumnName)) { - return $class->getFieldNameForLowerColumnName($lcColumnName); + if ($class->hasField($fieldName)) { + //return $class->getFieldNameForLowerColumnName($lcColumnName); + return $class; } - + foreach ($class->getSubclasses() as $subClass) { - $subClassMetadata = Doctrine_ORM_Mapping_ClassMetadataFactory::getInstance() - ->getMetadataFor($subClass); - if ($subClassMetadata->hasLowerColumn($lcColumnName)) { - return $subClassMetadata->getFieldNameForLowerColumnName($lcColumnName); + $subClassMetadata = $this->_em->getClassMetadata($subClass); + if ($subClassMetadata->hasField($fieldName)) { + //return $subClassMetadata->getFieldNameForLowerColumnName($lcColumnName); + return $subClassMetadata; } } - throw DoctrineException::updateMe("No field name found for column name '$lcColumnName' during hydration."); + throw DoctrineException::updateMe("No owner found for field '$fieldName' during hydration."); } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php index 1f5230cf2..2d2a655dc 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php @@ -30,8 +30,7 @@ use \PDO; */ class ArrayHydrator extends AbstractHydrator { - private $_rootAlias; - private $_rootEntityName; + private $_rootAliases = array(); private $_isSimpleQuery = false; private $_identifierMap = array(); private $_resultPointers = array(); @@ -42,14 +41,12 @@ class ArrayHydrator extends AbstractHydrator protected function _prepare($parserResult) { parent::_prepare($parserResult); - $this->_rootAlias = $parserResult->getDefaultQueryComponentAlias(); - $this->_rootEntityName = $this->_queryComponents[$this->_rootAlias]['metadata']->getClassName(); - $this->_isSimpleQuery = count($this->_queryComponents) <= 1; + $this->_isSimpleQuery = $this->_resultSetMapping->getEntityResultCount() <= 1; $this->_identifierMap = array(); $this->_resultPointers = array(); $this->_idTemplate = array(); $this->_resultCounter = 0; - foreach ($this->_queryComponents as $dqlAlias => $component) { + foreach ($this->_resultSetMapping->getAliasMap() as $dqlAlias => $class) { $this->_identifierMap[$dqlAlias] = array(); $this->_resultPointers[$dqlAlias] = array(); $this->_idTemplate[$dqlAlias] = ''; @@ -80,36 +77,6 @@ class ArrayHydrator extends AbstractHydrator $id = $this->_idTemplate; // initialize the id-memory $nonemptyComponents = array(); $rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents); - $rootAlias = $this->_rootAlias; - - // 2) Hydrate the data of the root entity from the current row - // Check for an existing element - $index = false; - if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$rootAlias][$id[$rootAlias]])) { - $element = $rowData[$rootAlias]; - if ($field = $this->_getCustomIndexField($rootAlias)) { - if ($this->_parserResult->isMixedQuery()) { - $result[] = array($element[$field] => $element); - ++$this->_resultCounter; - } else { - $result[$element[$field]] = $element; - } - } else { - if ($this->_parserResult->isMixedQuery()) { - $result[] = array($element); - ++$this->_resultCounter; - } else { - $result[] = $element; - } - } - end($result); - $this->_identifierMap[$rootAlias][$id[$rootAlias]] = key($result); - } else { - $index = $this->_identifierMap[$rootAlias][$id[$rootAlias]]; - } - $this->updateResultPointer($result, $index, $rootAlias, false); - unset($rowData[$rootAlias]); - // end of hydrate data of the root component for the current row // Extract scalar values. They're appended at the end. if (isset($rowData['scalars'])) { @@ -121,61 +88,94 @@ class ArrayHydrator extends AbstractHydrator // belongs to other (related) entities. foreach ($rowData as $dqlAlias => $data) { $index = false; - $map = $this->_queryComponents[$dqlAlias]; - $parent = $map['parent']; - $relationAlias = $map['relation']->getSourceFieldName(); - $path = $parent . '.' . $dqlAlias; - // Get a reference to the right element in the result tree. - // This element will get the associated element attached. - if ($this->_parserResult->isMixedQuery() && $parent == $rootAlias) { - $key = key(reset($this->_resultPointers)); - // TODO: Exception if $key === null ? - $baseElement =& $this->_resultPointers[$parent][$key]; - } else if (isset($this->_resultPointers[$parent])) { - $baseElement =& $this->_resultPointers[$parent]; - } else { - unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 - continue; - } + if ($this->_resultSetMapping->hasParentAlias($dqlAlias)) { - // Check the type of the relation (many or single-valued) - if ( ! $map['relation']->isOneToOne()) { - $oneToOne = false; - if (isset($nonemptyComponents[$dqlAlias])) { - if ( ! isset($baseElement[$relationAlias])) { + $parent = $this->_resultSetMapping->getParentAlias($dqlAlias); + $relation = $this->_resultSetMapping->getRelation($dqlAlias); + $relationAlias = $relation->getSourceFieldName(); + $path = $parent . '.' . $dqlAlias; + + // Get a reference to the right element in the result tree. + // This element will get the associated element attached. + if ($this->_parserResult->isMixedQuery() && isset($this->_rootAliases[$parent])) { + $key = key(reset($this->_resultPointers)); + // TODO: Exception if $key === null ? + $baseElement =& $this->_resultPointers[$parent][$key]; + } else if (isset($this->_resultPointers[$parent])) { + $baseElement =& $this->_resultPointers[$parent]; + } else { + unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 + continue; + } + + // Check the type of the relation (many or single-valued) + if ( ! $relation->isOneToOne()) { + $oneToOne = false; + if (isset($nonemptyComponents[$dqlAlias])) { + if ( ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = array(); + } + $indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]); + $index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; + $indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false; + if ( ! $indexExists || ! $indexIsValid) { + $element = $data; + if ($field = $this->_getCustomIndexField($dqlAlias)) { + $baseElement[$relationAlias][$element[$field]] = $element; + } else { + $baseElement[$relationAlias][] = $element; + } + end($baseElement[$relationAlias]); + $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = + key($baseElement[$relationAlias]); + } + } else if ( ! isset($baseElement[$relationAlias])) { $baseElement[$relationAlias] = array(); } - $indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]); - $index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; - $indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false; - if ( ! $indexExists || ! $indexIsValid) { - $element = $data; - if ($field = $this->_getCustomIndexField($dqlAlias)) { - $baseElement[$relationAlias][$element[$field]] = $element; - } else { - $baseElement[$relationAlias][] = $element; - } - end($baseElement[$relationAlias]); - $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = - key($baseElement[$relationAlias]); + } else { + $oneToOne = true; + if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = null; + } else if ( ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = $data; } - } else if ( ! isset($baseElement[$relationAlias])) { - $baseElement[$relationAlias] = array(); } + + $coll =& $baseElement[$relationAlias]; + + if ($coll !== null) { + $this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne); + } + } else { - $oneToOne = true; - if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) { - $baseElement[$relationAlias] = null; - } else if ( ! isset($baseElement[$relationAlias])) { - $baseElement[$relationAlias] = $data; + $this->_rootAliases[$dqlAlias] = true; // Mark as root + // 2) Hydrate the data of the root entity from the current row + // Check for an existing element + if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { + $element = $rowData[$dqlAlias]; + if ($field = $this->_getCustomIndexField($dqlAlias)) { + if ($this->_parserResult->isMixedQuery()) { + $result[] = array($element[$field] => $element); + ++$this->_resultCounter; + } else { + $result[$element[$field]] = $element; + } + } else { + if ($this->_parserResult->isMixedQuery()) { + $result[] = array($element); + ++$this->_resultCounter; + } else { + $result[] = $element; + } + } + end($result); + $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result); + } else { + $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; } - } - - $coll =& $baseElement[$relationAlias]; - - if ($coll !== null) { - $this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne); + $this->updateResultPointer($result, $index, $dqlAlias, false); + //unset($rowData[$rootAlias]); } } diff --git a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php index f51421582..ac1386e00 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php @@ -37,25 +37,23 @@ class ObjectHydrator extends AbstractHydrator /** Memory for initialized relations */ private $_initializedRelations = array(); private $_metadataMap = array(); - private $_rootAlias; - private $_rootEntityName; + private $_rootAliases = array(); private $_isSimpleQuery = false; private $_identifierMap = array(); private $_resultPointers = array(); private $_idTemplate = array(); private $_resultCounter = 0; + /** @override */ protected function _prepare($parserResult) { parent::_prepare($parserResult); - $this->_rootAlias = $parserResult->getDefaultQueryComponentAlias(); - $this->_rootEntityName = $this->_queryComponents[$this->_rootAlias]['metadata']->getClassName(); - $this->_isSimpleQuery = count($this->_queryComponents) <= 1; + $this->_isSimpleQuery = $this->_resultSetMapping->getEntityResultCount() <= 1; $this->_identifierMap = array(); $this->_resultPointers = array(); $this->_idTemplate = array(); $this->_resultCounter = 0; - foreach ($this->_queryComponents as $dqlAlias => $component) { + foreach ($this->_resultSetMapping->getAliasMap() as $dqlAlias => $class) { $this->_identifierMap[$dqlAlias] = array(); $this->_resultPointers[$dqlAlias] = array(); $this->_idTemplate[$dqlAlias] = ''; @@ -158,8 +156,10 @@ class ObjectHydrator extends AbstractHydrator private function isIndexKeyInUse($entity, $assocField, $indexField) { - return $this->_metadataMap[spl_object_hash($entity)]->getReflectionProperty($assocField) - ->getValue($entity)->containsKey($indexField); + return $this->_metadataMap[spl_object_hash($entity)] + ->getReflectionProperty($assocField) + ->getValue($entity) + ->containsKey($indexField); } private function getLastKey($coll) @@ -268,42 +268,6 @@ class ObjectHydrator extends AbstractHydrator $id = $this->_idTemplate; // initialize the id-memory $nonemptyComponents = array(); $rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents); - $rootAlias = $this->_rootAlias; - - // 2) Hydrate the data of the root entity from the current row - // Check for an existing element - $index = false; - if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$rootAlias][$id[$rootAlias]])) { - $element = $this->_uow->createEntity($this->_rootEntityName, $rowData[$rootAlias]); - $oid = spl_object_hash($element); - $this->_metadataMap[$oid] = $this->_em->getClassMetadata($this->_rootEntityName); - if ($field = $this->_getCustomIndexField($rootAlias)) { - if ($this->_parserResult->isMixedQuery()) { - $result[] = array( - $this->_metadataMap[$oid]->getReflectionProperty($field) - ->getValue($element) => $element - ); - ++$this->_resultCounter; - } else { - $result->set($element, $this->_metadataMap[$oid] - ->getReflectionProperty($field) - ->getValue($element)); - } - } else { - if ($this->_parserResult->isMixedQuery()) { - $result[] = array($element); - ++$this->_resultCounter; - } else { - $result->add($element); - } - } - $this->_identifierMap[$rootAlias][$id[$rootAlias]] = $this->getLastKey($result); - } else { - $index = $this->_identifierMap[$rootAlias][$id[$rootAlias]]; - } - $this->updateResultPointer($result, $index, $rootAlias, false); - unset($rowData[$rootAlias]); - // end hydrate data of the root component for the current row // Extract scalar values. They're appended at the end. if (isset($rowData['scalars'])) { @@ -311,73 +275,113 @@ class ObjectHydrator extends AbstractHydrator unset($rowData['scalars']); } - // 3) Now hydrate the rest of the data found in the current row, that - // belongs to other (related) entities. + // Now hydrate the entity data found in the current row. foreach ($rowData as $dqlAlias => $data) { $index = false; - $map = $this->_queryComponents[$dqlAlias]; - $entityName = $map['metadata']->getClassName(); - $parent = $map['parent']; - $relationAlias = $map['relation']->getSourceFieldName(); - $path = $parent . '.' . $dqlAlias; + $entityName = $this->_resultSetMapping->getClass($dqlAlias)->getClassName(); + + if ($this->_resultSetMapping->hasParentAlias($dqlAlias)) { + // It's a joined result + + $parent = $this->_resultSetMapping->getParentAlias($dqlAlias); + $relation = $this->_resultSetMapping->getRelation($dqlAlias); + $relationAlias = $relation->getSourceFieldName(); + $path = $parent . '.' . $dqlAlias; - // Get a reference to the right element in the result tree. - // This element will get the associated element attached. - if ($this->_parserResult->isMixedQuery() && $parent == $rootAlias) { - $key = key(reset($this->_resultPointers)); - // TODO: Exception if $key === null ? - $baseElement =& $this->_resultPointers[$parent][$key]; - } else if (isset($this->_resultPointers[$parent])) { - $baseElement =& $this->_resultPointers[$parent]; - } else { - unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 - continue; - } + // Get a reference to the right element in the result tree. + // This element will get the associated element attached. + if ($this->_parserResult->isMixedQuery() && isset($this->_rootAliases[$parent])) { + $key = key(reset($this->_resultPointers)); + // TODO: Exception if $key === null ? + $baseElement =& $this->_resultPointers[$parent][$key]; + } else if (isset($this->_resultPointers[$parent])) { + $baseElement =& $this->_resultPointers[$parent]; + } else { + unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 + continue; + } - $oid = spl_object_hash($baseElement); + $oid = spl_object_hash($baseElement); - // Check the type of the relation (many or single-valued) - if ( ! $map['relation']->isOneToOne()) { - $oneToOne = false; - if (isset($nonemptyComponents[$dqlAlias])) { - $this->initRelatedCollection($baseElement, $relationAlias); - $indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]); - $index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; - $indexIsValid = $index !== false ? $this->isIndexKeyInUse($baseElement, $relationAlias, $index) : false; - if ( ! $indexExists || ! $indexIsValid) { - $element = $this->getEntity($data, $entityName); - if ($field = $this->_getCustomIndexField($dqlAlias)) { - $this->addRelatedIndexedEntity($baseElement, $relationAlias, $element, $field); - } else { - $this->addRelatedEntity($baseElement, $relationAlias, $element); + // Check the type of the relation (many or single-valued) + if ( ! $relation->isOneToOne()) { + $oneToOne = false; + if (isset($nonemptyComponents[$dqlAlias])) { + $this->initRelatedCollection($baseElement, $relationAlias); + $indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]); + $index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; + $indexIsValid = $index !== false ? $this->isIndexKeyInUse($baseElement, $relationAlias, $index) : false; + if ( ! $indexExists || ! $indexIsValid) { + $element = $this->getEntity($data, $entityName); + if ($field = $this->_getCustomIndexField($dqlAlias)) { + $this->addRelatedIndexedEntity($baseElement, $relationAlias, $element, $field); + } else { + $this->addRelatedEntity($baseElement, $relationAlias, $element); + } + $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = $this->getLastKey( + $this->_metadataMap[$oid] + ->getReflectionProperty($relationAlias) + ->getValue($baseElement)); } - $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = $this->getLastKey( - $this->_metadataMap[$oid] - ->getReflectionProperty($relationAlias) - ->getValue($baseElement)); + } else if ( ! $this->isFieldSet($baseElement, $relationAlias)) { + $coll = new PersistentCollection($this->_em, $entityName); + $this->_collections[] = $coll; + $this->setRelatedElement($baseElement, $relationAlias, $coll); } - } else if ( ! $this->isFieldSet($baseElement, $relationAlias)) { - $coll = new PersistentCollection($this->_em, $entityName); - $this->_collections[] = $coll; - $this->setRelatedElement($baseElement, $relationAlias, $coll); + } else { + $oneToOne = true; + if ( ! isset($nonemptyComponents[$dqlAlias]) && + ! $this->isFieldSet($baseElement, $relationAlias)) { + $this->setRelatedElement($baseElement, $relationAlias, null); + } else if ( ! $this->isFieldSet($baseElement, $relationAlias)) { + $this->setRelatedElement($baseElement, $relationAlias, + $this->getEntity($data, $entityName)); + } + } + + $coll = $this->_metadataMap[$oid] + ->getReflectionProperty($relationAlias) + ->getValue($baseElement); + + if ($coll !== null) { + $this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne); } } else { - $oneToOne = true; - if ( ! isset($nonemptyComponents[$dqlAlias]) && - ! $this->isFieldSet($baseElement, $relationAlias)) { - $this->setRelatedElement($baseElement, $relationAlias, null); - } else if ( ! $this->isFieldSet($baseElement, $relationAlias)) { - $this->setRelatedElement($baseElement, $relationAlias, - $this->getEntity($data, $entityName)); + // Its a root result element + + $this->_rootAliases[$dqlAlias] = true; // Mark as root alias + + if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { + $element = $this->_uow->createEntity($entityName, $rowData[$dqlAlias]); + $oid = spl_object_hash($element); + $this->_metadataMap[$oid] = $this->_em->getClassMetadata($entityName); + if ($field = $this->_getCustomIndexField($dqlAlias)) { + if ($this->_parserResult->isMixedQuery()) { + $result[] = array( + $this->_metadataMap[$oid] + ->getReflectionProperty($field) + ->getValue($element) => $element + ); + ++$this->_resultCounter; + } else { + $result->set($element, $this->_metadataMap[$oid] + ->getReflectionProperty($field) + ->getValue($element)); + } + } else { + if ($this->_parserResult->isMixedQuery()) { + $result[] = array($element); + ++$this->_resultCounter; + } else { + $result->add($element); + } + } + $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->getLastKey($result); + } else { + $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; } - } - - $coll = $this->_metadataMap[$oid] - ->getReflectionProperty($relationAlias) - ->getValue($baseElement); - - if ($coll !== null) { - $this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne); + $this->updateResultPointer($result, $index, $dqlAlias, false); + //unset($rowData[$dqlAlias]); } } diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/lib/Doctrine/ORM/Mapping/ClassMetadata.php index c9c7ef682..8246397a5 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadata.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadata.php @@ -84,6 +84,26 @@ final class ClassMetadata * must have a natural id. */ const GENERATOR_TYPE_NONE = 'none'; + /** + * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time + * by doing a property-by-property comparison with the original data. This will + * be done for all entities that are in MANAGED state at commit-time. + * + * This is the default change tracking policy. + */ + const CHANGETRACKING_DEFERRED_IMPLICIT = 1; + /** + * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time + * by doing a property-by-property comparison with the original data. This will + * be done only for entities that were explicitly saved (through save() or cascade). + */ + const CHANGETRACKING_DEFERRED_EXPLICIT = 2; + /** + * NOTIFY means that Doctrine relies on the entities sending out notifications + * when their properties change. Such entity classes must implement + * the NotifyPropertyChanged interface. + */ + const CHANGETRACKING_NOTIFY = 3; /** * The name of the entity class. @@ -333,13 +353,6 @@ final class ClassMetadata private $_reflectionProperties; //private $_insertSql; - /** - * The name of the ID generator used for this class. Only used for SEQUENCE - * and TABLE generation strategies. - * - * @var string - */ - //private $_idGeneratorName; /** * The ID generator used for generating IDs for this class. @@ -364,6 +377,13 @@ final class ClassMetadata */ //private $_tableGeneratorDefinition; + /** + * The policy used for change-tracking on entities of this class. + * + * @var integer + */ + //private $_changeTrackingPolicy; + /** * Initializes a new ClassMetadata instance that will hold the object-relational mapping * metadata of the class with the given name. @@ -399,6 +419,18 @@ final class ClassMetadata return $this->_reflectionProperties; } + /** + * INTERNAL: + * Adds a reflection property. Usually only used by the ClassMetadataFactory + * while processing inheritance mappings. + * + * @param array $props + */ + public function addReflectionProperty($propName, \ReflectionProperty $property) + { + $this->_reflectionProperties[$propName] = $property; + } + /** * Gets a ReflectionProperty for a specific field of the mapped class. * @@ -434,6 +466,23 @@ final class ClassMetadata return $this->_entityName; } + /** + * Gets the name of the class in the entity hierarchy that owns the field with + * the given name. The owning class is the one that defines the field. + * + * @param string $fieldName + * @return string + */ + public function getOwningClass($fieldName) + { + if ($this->_inheritanceType == self::INHERITANCE_TYPE_NONE) { + return $this->_entityName; + } else { + $mapping = $this->getFieldMapping($fieldName); + return $mapping['inherited']; + } + } + /** * Gets the name of the root class of the mapped entity hierarchy. If the entity described * by this ClassMetadata instance is not participating in a hierarchy, this is the same as the @@ -755,6 +804,13 @@ final class ClassMetadata return $this->getColumnName($this->getSingleIdentifierFieldName()); } + /** + * INTERNAL: + * Sets the mapped identifier/primary key fields of this class. + * Mainly used by the ClassMetadataFactory to assign inherited identifiers. + * + * @param array $identifier + */ public function setIdentifier(array $identifier) { $this->_identifier = $identifier; @@ -1176,7 +1232,7 @@ final class ClassMetadata { $this->_validateAndCompleteFieldMapping($mapping); if (isset($this->_fieldMappings[$mapping['fieldName']])) { - throw MappingException::duplicateFieldMapping(); + throw MappingException::duplicateFieldMapping($mapping['fieldName']); } $this->_fieldMappings[$mapping['fieldName']] = $mapping; } @@ -1193,6 +1249,18 @@ final class ClassMetadata $this->_storeAssociationMapping($mapping); } + /** + * INTERNAL: + * Adds an association mapping without completing/validating it. + * This is mainly used to add inherited field mappings to derived classes. + * + * @param array $mapping + */ + public function addFieldMapping(array $fieldMapping) + { + $this->_fieldMappings[$fieldMapping['fieldName']] = $fieldMapping; + } + /** * Adds a one-to-one mapping. * diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index 7083d086e..d807ff1ed 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -131,6 +131,7 @@ class ClassMetadataFactory $class->setIdGeneratorType($parent->getIdGeneratorType()); $this->_addInheritedFields($class, $parent); $this->_addInheritedRelations($class, $parent); + $class->setIdentifier($parent->getIdentifier()); } // Invoke driver @@ -176,7 +177,8 @@ class ClassMetadataFactory if ( ! isset($mapping['inherited'])) { $mapping['inherited'] = $parentClass->getClassName(); } - $subClass->mapField($mapping); + $subClass->addFieldMapping($mapping); + $subClass->addReflectionProperty($fieldName, $parentClass->getReflectionProperty($fieldName)); } } diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index 9908d89db..7af2d46bd 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -77,8 +77,8 @@ class AnnotationDriver } // Evaluate DoctrineDiscriminatorMap annotation - if ($discrValueAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorMap')) { - $metadata->setDiscriminatorMap((array)$discrValueAnnot->value); + if ($discrMapAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorMap')) { + $metadata->setDiscriminatorMap((array)$discrMapAnnot->value); } // Evaluate DoctrineSubClasses annotation @@ -88,6 +88,10 @@ class AnnotationDriver // Evaluate annotations on properties/fields foreach ($annotClass->getProperties() as $property) { + if ($metadata->hasField($property->getName())) { + continue; + } + $mapping = array(); $mapping['fieldName'] = $property->getName(); diff --git a/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php b/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php index 7d145ed23..1719af4ae 100644 --- a/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php @@ -43,7 +43,7 @@ abstract class AbstractEntityPersister protected $_classMetadata; /** - * The name of the Entity the persister is used for. + * The name of the entity the persister is used for. * * @var string */ @@ -123,6 +123,7 @@ abstract class AbstractEntityPersister foreach ($this->_queuedInserts as $insertData) { $stmt->execute(array_values($insertData)); } + $this->_queuedInserts = array(); } /** @@ -153,7 +154,18 @@ abstract class AbstractEntityPersister $this->_conn->delete($this->_classMetadata->getTableName(), $id); } + public function addDelete($entity) + { + + } + + public function executeDeletions() + { + + } + /** + * Gets the ClassMetadata instance of the entity class this persister is used for. * * @return Doctrine\ORM\Mapping\ClassMetadata */ @@ -169,25 +181,6 @@ abstract class AbstractEntityPersister { //... } - - /** - * Gets the name of the class in the entity hierarchy that owns the field with - * the given name. The owning class is the one that defines the field. - * - * @param string $fieldName - * @return string - * @todo Move to ClassMetadata? - */ - public function getOwningClass($fieldName) - { - if ($this->_classMetadata->isInheritanceTypeNone()) { - return $this->_classMetadata; - } else { - $mapping = $this->_classMetadata->getFieldMapping($fieldName); - return $mapping['inherited']; - } - \Doctrine\Common\DoctrineException::updateMe("Unable to find defining class of field '$fieldName'."); - } /** * Callback that is invoked during the SQL construction process. @@ -204,6 +197,16 @@ abstract class AbstractEntityPersister { return array(); } + + /** + * Gets all field mappings of the entire entity hierarchy. + * + * @return array + */ + public function getAllFieldMappingsInHierarchy() + { + return $this->_classMetadata->getFieldMappings(); + } /** * Prepares the data of an entity for an insert/update operation. @@ -241,13 +244,13 @@ abstract class AbstractEntityPersister $result[$columnName] = $type->convertToDatabaseValue($newVal, $this->_conn->getDatabasePlatform()); } } - + /* // Populate the discriminator column on insert in JOINED & SINGLE_TABLE inheritance if ($isInsert && ($this->_classMetadata->isInheritanceTypeJoined() || $this->_classMetadata->isInheritanceTypeSingleTable())) { $discColumn = $this->_classMetadata->getDiscriminatorColumn(); $discMap = $this->_classMetadata->getDiscriminatorMap(); $result[$discColumn['name']] = array_search($this->_entityName, $discMap); - } + }*/ } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Persisters/SingleTablePersister.php b/lib/Doctrine/ORM/Persisters/SingleTablePersister.php index 9da608243..4ac28aa3d 100644 --- a/lib/Doctrine/ORM/Persisters/SingleTablePersister.php +++ b/lib/Doctrine/ORM/Persisters/SingleTablePersister.php @@ -4,5 +4,37 @@ namespace Doctrine\ORM\Persisters; class SingleTablePersister extends AbstractEntityPersister { - + //private $_selectColumnList = array(); + + public function insert($entity) + { + return parent::insert($entity); + } + + /** @override */ + protected function _prepareData($entity, array &$result, $isInsert = false) + { + parent::_prepareData($entity, $result, $isInsert); + // Populate the discriminator column + if ($isInsert) { + $discColumn = $this->_classMetadata->getDiscriminatorColumn(); + $discMap = $this->_classMetadata->getDiscriminatorMap(); + $result[$discColumn['name']] = array_search($this->_entityName, $discMap); + } + } + + /** + * {@inheritdoc} + */ + /*public function getAllFieldMappingsInHierarchy() + { + $fieldMappings = $this->_classMetadata->getFieldMappings(); + foreach ($this->_classMetadata->getSubclasses() as $subclassName) { + $fieldMappings = array_merge( + $fieldMappings, + $this->_em->getClassMetadata($subclassName)->getFieldMappings() + ); + } + return $fieldMappings; + }*/ } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php index 033c93d17..d04f2ceee 100644 --- a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php @@ -16,7 +16,7 @@ * * This software consists of voluntary contributions made by many individuals * and is licensed under the LGPL. For more information, see - * . + * . */ namespace Doctrine\ORM\Persisters; @@ -38,22 +38,6 @@ class StandardEntityPersister extends AbstractEntityPersister */ protected function _doDelete($record) { - /*try { - $this->_conn->beginInternalTransaction(); - $this->_deleteComposites($record); - - $record->_state(Doctrine_ORM_Entity::STATE_TDIRTY); - - $identifier = $this->_convertFieldToColumnNames($record->identifier(), $metadata); - $this->_deleteRow($metadata->getTableName(), $identifier); - $record->_state(Doctrine_ORM_Entity::STATE_TCLEAN); - - $this->removeRecord($record); - $conn->commit(); - } catch (Exception $e) { - $conn->rollback(); - throw $e; - }*/ } /** @@ -63,41 +47,6 @@ class StandardEntityPersister extends AbstractEntityPersister */ protected function _doInsert(Doctrine_ORM_Entity $record) { - $fields = $record->getPrepared(); - if (empty($fields)) { - return false; - } - - $class = $this->_classMetadata; - $identifier = $class->getIdentifier(); - $fields = $this->_convertFieldToColumnNames($fields, $class); - - $seq = $class->getTableOption('sequenceName'); - if ( ! empty($seq)) { - $id = $conn->sequence->nextId($seq); - $seqName = $identifier[0]; - $fields[$seqName] = $id; - $record->assignIdentifier($id); - } - - $this->_insertRow($class->getTableName(), $fields); - - if (empty($seq) && count($identifier) == 1 && - $class->getIdentifierType() != Doctrine::IDENTIFIER_NATURAL) { - if (strtolower($conn->getName()) == 'pgsql') { - $seq = $class->getTableName() . '_' . $identifier[0]; - } - - $id = $conn->sequence->lastInsertId($seq); - - if ( ! $id) { - throw \Doctrine\Common\DoctrineException::updateMe("Couldn't get last insert identifier."); - } - - $record->assignIdentifier($id); - } else { - $record->assignIdentifier(true); - } } /** @@ -105,11 +54,5 @@ class StandardEntityPersister extends AbstractEntityPersister */ protected function _doUpdate(Doctrine_ORM_Entity $record) { - $conn = $this->_conn; - $classMetadata = $this->_classMetadata; - $identifier = $this->_convertFieldToColumnNames($record->identifier(), $classMetadata); - $data = $this->_convertFieldToColumnNames($record->getPrepared(), $classMetadata); - $this->_updateRow($classMetadata->getTableName(), $data, $identifier); - $record->assignIdentifier(true); } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index 9349d718a..13ec757cc 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -227,6 +227,10 @@ class Query extends AbstractQuery */ public function execute($params = array(), $hydrationMode = null) { + if ($this->_em->getUnitOfWork()->hasPendingInsertions()) { + $this->_em->flush(); + } + if ($hydrationMode !== null) { $this->_hydrationMode = $hydrationMode; } @@ -496,6 +500,16 @@ class Query extends AbstractQuery $this->_hydrationMode = $hydrationMode; return $this; } + + /** + * Gets the hydration mode currently used by the query. + * + * @return integer + */ + public function getHydrationMode() + { + return $this->_hydrationMode; + } /** * Gets the list of results for the query. diff --git a/lib/Doctrine/ORM/Query/AbstractResult.php b/lib/Doctrine/ORM/Query/AbstractResult.php index cf95e7bdb..9997c112e 100644 --- a/lib/Doctrine/ORM/Query/AbstractResult.php +++ b/lib/Doctrine/ORM/Query/AbstractResult.php @@ -51,12 +51,12 @@ abstract class AbstractResult * parent Alias of the parent. * map Name of the column / aggregate value this component is mapped to a collection. */ - protected $_queryComponents = array(); + //protected $_queryComponents = array(); /** * @var array Table alias map. Keys are SQL aliases and values DQL aliases. */ - protected $_tableAliasMap = array(); + //protected $_tableAliasMap = array(); /** * @var array Enum params. @@ -66,7 +66,7 @@ abstract class AbstractResult /** * @var string */ - protected $_defaultQueryComponentAlias; + //protected $_defaultQueryComponentAlias; /** * @var boolean @@ -78,10 +78,10 @@ abstract class AbstractResult * * @param array $queryComponents Query components. */ - public function setQueryComponents(array $queryComponents) + /*public function setQueryComponents(array $queryComponents) { $this->_queryComponents = $queryComponents; - } + }*/ /** * Sets the declaration for given component alias. @@ -89,38 +89,38 @@ abstract class AbstractResult * @param string $componentAlias The component alias to set the declaration to. * @param string $queryComponent Alias declaration. */ - public function setQueryComponent($componentAlias, array $queryComponent) + /*public function setQueryComponent($componentAlias, array $queryComponent) { $this->_queryComponents[$componentAlias] = $queryComponent; - } + }*/ /** * Gets the mapping components. * * @return array Query components. */ - public function getQueryComponents() + /*public function getQueryComponents() { return $this->_queryComponents; - } + }*/ /** * */ - public function getDefaultQueryComponentAlias() + /*public function getDefaultQueryComponentAlias() { return $this->_defaultQueryComponentAlias; - } + }*/ /** * * * @param $alias */ - public function setDefaultQueryComponentAlias($alias) + /*public function setDefaultQueryComponentAlias($alias) { $this->_defaultQueryComponentAlias = $alias; - } + }*/ /** * Get the declaration for given component alias. @@ -128,14 +128,14 @@ abstract class AbstractResult * @param string $componentAlias The component alias the retrieve the declaration from. * @return array Alias declaration. */ - public function getQueryComponent($componentAlias) + /*public function getQueryComponent($componentAlias) { if ( ! isset($this->_queryComponents[$componentAlias])) { throw new DoctrineException('Unknown query component ' . $componentAlias); } return $this->_queryComponents[$componentAlias]; - } + }*/ /** * Get the component alias for a given query component @@ -143,10 +143,10 @@ abstract class AbstractResult * @param array $queryComponent The query component * @param string Component alias */ - public function getComponentAlias($queryComponent) + /*public function getComponentAlias($queryComponent) { return array_search($queryComponent, $this->_queryComponents);; - } + }*/ /** * Whether or not this object has a declaration for given component alias. @@ -154,20 +154,20 @@ abstract class AbstractResult * @param string $componentAlias Component alias the retrieve the declaration from. * @return boolean True if this object has given alias, otherwise false. */ - public function hasQueryComponent($componentAlias) + /*public function hasQueryComponent($componentAlias) { return isset($this->_queryComponents[$componentAlias]); - } + }*/ /** * Defines the table aliases. * * @param array $tableAliasMap Table aliases. */ - public function setTableAliasMap(array $tableAliasMap) + /*public function setTableAliasMap(array $tableAliasMap) { $this->_tableAliasMap = $tableAliasMap; - } + }*/ /** * Adds an SQL table alias and associates it a component alias @@ -175,20 +175,20 @@ abstract class AbstractResult * @param string $tableAlias Table alias to be added. * @param string $componentAlias Alias for the query component associated with given tableAlias. */ - public function setTableAlias($tableAlias, $componentAlias) + /*public function setTableAlias($tableAlias, $componentAlias) { $this->_tableAliasMap[$tableAlias] = $componentAlias; - } + }*/ /** * Returns all table aliases. * * @return array Table aliases as an array. */ - public function getTableAliasMap() + /*public function getTableAliasMap() { return $this->_tableAliasMap; - } + }*/ /** * Get DQL alias associated with given SQL table alias. @@ -196,14 +196,14 @@ abstract class AbstractResult * @param string $tableAlias SQL table alias that identifies the component alias * @return string Component alias */ - public function getTableAlias($tableAlias) + /*public function getTableAlias($tableAlias) { if ( ! isset($this->_tableAliasMap[$tableAlias])) { throw DoctrineException::updateMe('Unknown table alias ' . $tableAlias); } return $this->_tableAliasMap[$tableAlias]; - } + }*/ /** * Get table alias associated with given component alias. @@ -211,10 +211,10 @@ abstract class AbstractResult * @param string $componentAlias Component alias that identifies the table alias * @return string Component alias */ - public function getTableAliasFromComponentAlias($componentAlias) + /*public function getTableAliasFromComponentAlias($componentAlias) { return array_search($componentAlias, $this->_tableAliasMap); - } + }*/ /** * Whether or not this object has given tableAlias. @@ -222,10 +222,10 @@ abstract class AbstractResult * @param string $tableAlias Table alias to be checked. * @return boolean True if this object has given alias, otherwise false. */ - public function hasTableAlias($tableAlias) + /*public function hasTableAlias($tableAlias) { return (isset($this->_tableAliasMap[$tableAlias])); - } + }*/ /** * Gets whether the parsed query selects objects/arrays and scalar values @@ -263,7 +263,7 @@ abstract class AbstractResult * @param string $key The key of the input parameter * @return Doctrine_ORM_Query_AbstractResult */ - public function addEnumParam($key, $table = null, $column = null) + /*public function addEnumParam($key, $table = null, $column = null) { $array = (isset($table) || isset($column)) ? array($table, $column) : array(); @@ -274,7 +274,7 @@ abstract class AbstractResult } return $this; - } + }*/ /** * Returns this object in serialized format, revertable using fromCached*. diff --git a/lib/Doctrine/ORM/Query/CacheHandler.php b/lib/Doctrine/ORM/Query/CacheHandler.php index 3385e06ab..7333c8cae 100644 --- a/lib/Doctrine/ORM/Query/CacheHandler.php +++ b/lib/Doctrine/ORM/Query/CacheHandler.php @@ -16,7 +16,7 @@ * * This software consists of voluntary contributions made by many individuals * and is licensed under the LGPL. For more information, see - * . + * . */ namespace Doctrine\ORM\Query; diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index db23bd186..6d7bbdeca 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -121,12 +121,22 @@ class Parser private $_resultContainsScalars = false; /** - * Whether the query is a SELECT query and contains objects in the result list + * Whether the query is a SELECT query and contains properties in the result list * as defined by the SelectExpressions. * * @var boolean */ - private $_resultContainsObjects = false; + private $_resultContainsProperties = false; + + /** + * Map of declared classes in the parsed query. + * Maps the declared DQL alias (key) to the class name (value). + * + * @var array + */ + //private $_declaredClasses = array(); + + private $_queryComponents = array(); /** * Creates a new query parser object. @@ -204,7 +214,7 @@ class Parser } // Create SqlWalker who creates the SQL from the AST - $sqlWalker = new SqlWalker($this->_em, $this->_parserResult); + $sqlWalker = new SqlWalker($this->_query, $this->_parserResult, $this->_queryComponents); // Assign an SQL executor to the parser result $this->_parserResult->setSqlExecutor(Exec\AbstractExecutor::create($AST, $sqlWalker)); @@ -388,7 +398,7 @@ class Parser private function _processDeferredPathExpressionStack() { $exprStack = array_pop($this->_deferredPathExpressionStacks); - $qComps = $this->_parserResult->getQueryComponents(); + $qComps = $this->_queryComponents; foreach ($exprStack as $expr) { $parts = $expr->getParts(); $numParts = count($parts); @@ -483,8 +493,7 @@ class Parser 'map' => null, 'scalar' => null, ); - $this->_parserResult->setQueryComponent($aliasIdentificationVariable, $queryComponent); - $this->_parserResult->setDefaultQueryComponentAlias($aliasIdentificationVariable); + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; $updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems); $updateClause->setAliasIdentificationVariable($aliasIdentificationVariable); @@ -504,7 +513,8 @@ class Parser $identVariable = $this->_lexer->token['value']; $this->match('.'); } else { - $identVariable = $this->_parserResult->getDefaultQueryComponentAlias(); + //$identVariable = $this->_parserResult->getDefaultQueryComponentAlias(); + throw new DoctrineException("Missing alias qualifier."); } $this->match(Lexer::T_IDENTIFIER); $field = $this->_lexer->token['value']; @@ -578,10 +588,9 @@ class Parser 'map' => null, 'scalar' => null, ); - $this->_parserResult->setQueryComponent($deleteClause->getAliasIdentificationVariable(), - $queryComponent); - $this->_parserResult->setDefaultQueryComponentAlias($deleteClause->getAliasIdentificationVariable()); - + $this->_queryComponents[$deleteClause->getAliasIdentificationVariable()] = $queryComponent; + //$this->_parserResult->setDefaultQueryComponentAlias($deleteClause->getAliasIdentificationVariable()); + //$this->_declaredClasses[$deleteClause->getAliasIdentificationVariable()] = $classMetadata; return $deleteClause; } @@ -620,11 +629,11 @@ class Parser $identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration(); $firstRangeDecl = $identificationVariableDeclarations[0]->getRangeVariableDeclaration(); - if ($firstRangeDecl->getAliasIdentificationVariable()) { + /*if ($firstRangeDecl->getAliasIdentificationVariable()) { $this->_parserResult->setDefaultQueryComponentAlias($firstRangeDecl->getAliasIdentificationVariable()); } else { $this->_parserResult->setDefaultQueryComponentAlias($firstRangeDecl->getAbstractSchemaName()); - } + }*/ while ($this->_lexer->isNextToken(',')) { $this->match(','); @@ -647,7 +656,7 @@ class Parser $peek = $this->_lexer->glimpse(); // First we recognize for an IdentificationVariable (DQL class alias) if ($peek['value'] != '.' && $peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { - $this->_resultContainsObjects = true; + $this->_resultContainsProperties = true; if ($this->_resultContainsScalars) { $this->_parserResult->setMixedQuery(true); } @@ -672,11 +681,11 @@ class Parser $fieldIdentificationVariable = $this->_lexer->token['value']; } $this->_resultContainsScalars = true; - if ($this->_resultContainsObjects) { + if ($this->_resultContainsProperties) { $this->_parserResult->setMixedQuery(true); } } else { - $this->_resultContainsObjects = true; + $this->_resultContainsProperties = true; if ($this->_resultContainsScalars) { $this->_parserResult->setMixedQuery(true); } @@ -739,7 +748,8 @@ class Parser 'map' => null, 'scalar' => null, ); - $this->_parserResult->setQueryComponent($aliasIdentificationVariable, $queryComponent); + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; + //$this->_declaredClasses[$aliasIdentificationVariable] = $classMetadata; return new AST\RangeVariableDeclaration( $classMetadata, $aliasIdentificationVariable @@ -807,8 +817,8 @@ class Parser // Verify that the association exists, if yes update the ParserResult // with the new component. - $parentComp = $this->_parserResult->getQueryComponent($joinPathExpression->getIdentificationVariable()); - $parentClass = $parentComp['metadata']; + //$parentComp = $this->_parserResult->getQueryComponent($joinPathExpression->getIdentificationVariable()); + $parentClass = $this->_queryComponents[$joinPathExpression->getIdentificationVariable()]['metadata']; $assocField = $joinPathExpression->getAssociationField(); if ( ! $parentClass->hasAssociation($assocField)) { $this->semanticalError("Class " . $parentClass->getClassName() . @@ -824,7 +834,8 @@ class Parser 'map' => null, 'scalar' => null, ); - $this->_parserResult->setQueryComponent($aliasIdentificationVariable, $joinQueryComponent); + $this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent; + //$this->_declaredClasses[$aliasIdentificationVariable] = $this->_em->getClassMetadata($targetClassName); // Create AST node $join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable); @@ -866,9 +877,7 @@ class Parser $this->match(Lexer::T_BY); $pathExp = $this->_SimpleStateFieldPathExpression(); // Add the INDEX BY info to the query component - $qComp = $this->_parserResult->getQueryComponent($pathExp->getIdentificationVariable()); - $qComp['map'] = $pathExp->getSimpleStateField(); - $this->_parserResult->setQueryComponent($pathExp->getIdentificationVariable(), $qComp); + $this->_queryComponents[$pathExp->getIdentificationVariable()]['map'] = $pathExp->getSimpleStateField(); return $pathExp; } @@ -909,10 +918,10 @@ class Parser $assocSeen = false; $identificationVariable = $this->_IdentificationVariable(); - if ( ! $this->_parserResult->hasQueryComponent($identificationVariable)) { + if ( ! isset($this->_queryComponents[$identificationVariable])) { $this->syntaxError("Identification variable."); } - $qComp = $this->_parserResult->getQueryComponent($identificationVariable); + $qComp = $this->_queryComponents[$identificationVariable]; $parts[] = $identificationVariable; $class = $qComp['metadata']; diff --git a/lib/Doctrine/ORM/Query/ParserResult.php b/lib/Doctrine/ORM/Query/ParserResult.php index edbf80feb..106d321b9 100644 --- a/lib/Doctrine/ORM/Query/ParserResult.php +++ b/lib/Doctrine/ORM/Query/ParserResult.php @@ -45,7 +45,35 @@ class ParserResult extends AbstractResult * * @var array $_queryFields */ - protected $_queryFields = array(); + //protected $_queryFields = array(); + + protected $_resultSetMapping; + + public function __construct() + { + $this->_resultSetMapping = new ResultSetMapping; + } + + /** + * Gets the ResultSetMapping for the parsed query. + * + * @return ResultSetMapping The result set mapping of the parsed query or NULL + * if the query is not a SELECT query. + */ + public function getResultSetMapping() + { + return $this->_resultSetMapping; + } + + /** + * Sets the ResultSetMapping of the parsed query. + * + * @param ResultSetMapping $rsm + */ + public function setResultSetMapping(ResultSetMapping $rsm) + { + $this->_resultSetMapping = $rsm; + } /** * Sets the Entity Manager. @@ -88,10 +116,10 @@ class ParserResult extends AbstractResult * * @param array $queryFields Query fields. */ - public function setQueryFields(array $queryFields) + /*public function setQueryFields(array $queryFields) { $this->_queryFields = $queryFields; - } + }*/ /** * Sets the declaration for given field alias. @@ -99,20 +127,20 @@ class ParserResult extends AbstractResult * @param string $fieldAlias The field alias to set the declaration to. * @param string $queryField Alias declaration. */ - public function setQueryField($fieldAlias, $queryField) + /*public function setQueryField($fieldAlias, $queryField) { $this->_queryFields[$fieldAlias] = $queryField; - } + }*/ /** * Gets the mapping fields. * * @return array Query fields. */ - public function getQueryFields() + /*public function getQueryFields() { return $this->_queryFields; - } + }*/ /** * Get the declaration for given field alias. @@ -120,14 +148,14 @@ class ParserResult extends AbstractResult * @param string $fieldAlias The field alias the retrieve the declaration from. * @return array Alias declaration. */ - public function getQueryField($fieldAlias) + /*public function getQueryField($fieldAlias) { if ( ! isset($this->_queryFields[$fieldAlias])) { throw DoctrineException::updateMe('Unknown query field ' . $fieldAlias); } return $this->_queryFields[$fieldAlias]; - } + }*/ /** * Whether or not this object has a declaration for given field alias. @@ -135,8 +163,8 @@ class ParserResult extends AbstractResult * @param string $fieldAlias Field alias the retrieve the declaration from. * @return boolean True if this object has given alias, otherwise false. */ - public function hasQueryField($fieldAlias) + /*public function hasQueryField($fieldAlias) { return isset($this->_queryFields[$fieldAlias]); - } + }*/ } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/ResultSetMapping.php b/lib/Doctrine/ORM/Query/ResultSetMapping.php new file mode 100644 index 000000000..e7272dc83 --- /dev/null +++ b/lib/Doctrine/ORM/Query/ResultSetMapping.php @@ -0,0 +1,205 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * A ResultSetMapping describes how a result set of an SQL query maps to a Doctrine result. + * + * @author Roman Borschel + * @since 2.0 + */ +class ResultSetMapping +{ + /** Maps alias names to ClassMetadata descriptors. */ + private $_aliasMap = array(); + /** Maps alias names to related association mappings. */ + private $_relationMap = array(); + /** Maps alias names to parent alias names. */ + private $_parentAliasMap = array(); + /** Maps column names in the result set to field names for each class. */ + private $_fieldMappings = array(); + /** Maps column names in the result set to the alias to use in the mapped result. */ + private $_scalarMappings = array(); + /** Maps column names in the result set to the alias they belong to. */ + private $_columnOwnerMap = array(); + /** Maps discriminator columns in the result set to the class they represent. */ + private $_discriminatorMap = array(); + /** Maps alias names to field names that should be used for indexing. */ + private $_indexByMap = array(); + + /** + * + * @param $class + * @param $alias The alias for this class. The alias must be unique within this ResultSetMapping. + * @param $discriminatorColumn + */ + public function addEntityResult($class, $alias, $discriminatorColumn = null) + { + $this->_aliasMap[$alias] = $class; + if ($discriminatorColumn !== null) { + $this->_discriminatorMap[$discriminatorColumn] = $class; + } + } + + public function addIndexBy($alias, $fieldName) + { + $this->_indexByMap[$alias] = $fieldName; + } + + public function hasIndexBy($alias) + { + return isset($this->_indexByMap[$alias]); + } + + public function getIndexByField($alias) + { + return $this->_indexByMap[$alias]; + } + + public function addFieldResult($alias, $columnName, $fieldName) + { + $this->_fieldMappings[$columnName] = $fieldName; + $this->_columnOwnerMap[$columnName] = $alias; + } + + public function addJoinedEntityResult($class, $alias, $parentAlias, $relation, $discriminatorColumn = null) + { + $this->_aliasMap[$alias] = $class; + $this->_parentAliasMap[$alias] = $parentAlias; + $this->_relationMap[$alias] = $relation; + if ($discriminatorColumn !== null) { + $this->_discriminatorMap[$discriminatorColumn] = $class; + } + } + + public function isDiscriminatorColumn($columnName) + { + return isset($this->_discriminatorMap[$columnName]); + } + + public function addScalarResult($columnName, $alias) + { + $this->_scalarMappings[$columnName] = $alias; + } + + /** + * @return boolean + */ + public function isScalarResult($columnName) + { + return isset($this->_scalarMappings[$columnName]); + } + + /** + * + * @param $alias + */ + public function getClass($alias) + { + if ( ! isset($this->_aliasMap[$alias])) { + var_dump($alias); die(); + } + return $this->_aliasMap[$alias]; + } + + /** + * Gets the alias for a column that is mapped as a scalar value. + * + * @param string $columnName + * @return string + */ + public function getScalarAlias($columnName) + { + return $this->_scalarMappings[$columnName]; + } + + /** + * Gets the class that owns the specified column. + * + * @param string $columnName + */ + public function getOwningClass($columnName) + { + return $this->_aliasMap[$this->_columnOwnerMap[$columnName]]; + } + + public function getRelation($alias) + { + return $this->_relationMap[$alias]; + } + + /** + * + * @param $columnName + * @return + */ + public function getEntityAlias($columnName) + { + return $this->_columnOwnerMap[$columnName]; + } + + /** + * + * @param $alias + * @return + */ + public function getParentAlias($alias) + { + return $this->_parentAliasMap[$alias]; + } + + public function hasParentAlias($alias) + { + return isset($this->_parentAliasMap[$alias]); + } + + /** + * + * @param $className + * @param $columnName + * @return + */ + public function getFieldName($columnName) + { + return $this->_fieldMappings[$columnName]; + } + + public function getAliasMap() + { + return $this->_aliasMap; + } + + public function getEntityResultCount() + { + return count($this->_aliasMap); + } + + + + /* TEMP */ + public function getRootAlias() + { + reset($this->_aliasMap); + return key($this->_aliasMap); + } +} + diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 260f8f0b2..72bc5ca88 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -36,34 +36,47 @@ use Doctrine\Common\DoctrineException; */ class SqlWalker { - const SQLALIAS_SEPARATOR = '__'; + //const SQLALIAS_SEPARATOR = '__'; + private $_resultSetMapping; + private $_aliasCounter = 0; private $_tableAliasCounter = 0; + private $_scalarResultCounter = 0; private $_parserResult; private $_em; + private $_query; private $_dqlToSqlAliasMap = array(); - private $_scalarAliasCounter = 0; + /** Map of all components/classes that appear in the DQL query. */ + private $_queryComponents = array(); + /** A list of classes that appear in non-scalar SelectExpressions. */ + private $_selectedClasses = array(); /** - * Initializes a new SqlWalker instance. + * Initializes a new SqlWalker instance with the given Query and ParserResult. + * + * @param Query $query The parsed Query. + * @param ParserResult $parserResult The result of the parsing process. */ - public function __construct($em, $parserResult) + public function __construct($query, $parserResult, array $queryComponents) { - $this->_em = $em; + $this->_resultSetMapping = $parserResult->getResultSetMapping(); + $this->_query = $query; + $this->_em = $query->getEntityManager(); $this->_parserResult = $parserResult; - $sqlToDqlAliasMap = array(Parser::SCALAR_QUERYCOMPONENT_ALIAS => Parser::SCALAR_QUERYCOMPONENT_ALIAS); + $this->_queryComponents = $queryComponents; + /*$sqlToDqlAliasMap = array(Parser::SCALAR_QUERYCOMPONENT_ALIAS => Parser::SCALAR_QUERYCOMPONENT_ALIAS); foreach ($parserResult->getQueryComponents() as $dqlAlias => $qComp) { $sqlAlias = $this->generateSqlTableAlias($qComp['metadata']->getTableName()); $sqlToDqlAliasMap[$sqlAlias] = $dqlAlias; } // SQL => DQL alias stored in ParserResult, needed for hydration. - $parserResult->setTableAliasMap($sqlToDqlAliasMap); + $parserResult->setTableAliasMap($sqlToDqlAliasMap);*/ // DQL => SQL alias stored only locally, needed for SQL construction. - $this->_dqlToSqlAliasMap = array_flip($sqlToDqlAliasMap); + //$this->_dqlToSqlAliasMap = array_flip($sqlToDqlAliasMap); // In a mixed query we start alias counting for scalars with 1 since // index 0 will hold the object. if ($parserResult->isMixedQuery()) { - $this->_scalarAliasCounter = 1; + $this->_scalarResultCounter = 1; } } @@ -97,9 +110,33 @@ class SqlWalker */ public function walkSelectClause($selectClause) { - return 'SELECT ' . (($selectClause->isDistinct()) ? 'DISTINCT ' : '') + $sql = 'SELECT ' . (($selectClause->isDistinct()) ? 'DISTINCT ' : '') . implode(', ', array_map(array($this, 'walkSelectExpression'), $selectClause->getSelectExpressions())); + // Append discriminator columns + /*if ($this->_query->getHydrationMode() == \Doctrine\ORM\Query::HYDRATE_OBJECT) { + foreach ($this->_selectedClasses as $dqlAlias => $class) { + if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) { + $tblAlias = $this->_dqlToSqlAliasMap[$dqlAlias]; + $discrColumn = $class->getDiscriminatorColumn(); + $sql .= ", $tblAlias." . $discrColumn['name'] . ' AS discr__' . $discrColumn['name']; + } + } + }*/ + + foreach ($this->_selectedClasses as $dqlAlias => $class) { + if ($this->_queryComponents[$dqlAlias]['relation'] === null) { + $this->_resultSetMapping->addEntityResult($class, $dqlAlias); + } else { + $this->_resultSetMapping->addJoinedEntityResult( + $class, $dqlAlias, + $this->_queryComponents[$dqlAlias]['parent'], + $this->_queryComponents[$dqlAlias]['relation'] + ); + } + } + + return $sql; } /** @@ -113,8 +150,10 @@ class SqlWalker $identificationVarDecls = $fromClause->getIdentificationVariableDeclarations(); $firstIdentificationVarDecl = $identificationVarDecls[0]; $rangeDecl = $firstIdentificationVarDecl->getRangeVariableDeclaration(); + $dqlAlias = $rangeDecl->getAliasIdentificationVariable(); + $sql .= $rangeDecl->getClassMetadata()->getTableName() . ' ' - . $this->_dqlToSqlAliasMap[$rangeDecl->getAliasIdentificationVariable()]; + . $this->getSqlTableAlias($rangeDecl->getClassMetadata()->getTableName()); foreach ($firstIdentificationVarDecl->getJoinVariableDeclarations() as $joinVarDecl) { $sql .= $this->walkJoinVariableDeclaration($joinVarDecl); @@ -158,9 +197,9 @@ class SqlWalker //TODO: support general SingleValuedPathExpression, not just state field $pathExpr = $orderByItem->getStateFieldPathExpression(); $parts = $pathExpr->getParts(); - $qComp = $this->_parserResult->getQueryComponent($parts[0]); + $qComp = $this->_queryComponents[$parts[0]]; $columnName = $qComp['metadata']->getColumnName($parts[1]); - $sql = $this->_dqlToSqlAliasMap[$parts[0]] . '.' . $columnName; + $sql = $this->getSqlTableAlias($qComp['metadata']->getTableName()) . '.' . $columnName; $sql .= $orderByItem->isAsc() ? ' ASC' : ' DESC'; return $sql; } @@ -195,11 +234,13 @@ class SqlWalker } $joinAssocPathExpr = $join->getJoinAssociationPathExpression(); - $sourceQComp = $this->_parserResult->getQueryComponent($joinAssocPathExpr->getIdentificationVariable()); - $targetQComp = $this->_parserResult->getQueryComponent($join->getAliasIdentificationVariable()); + $joinedDqlAlias = $join->getAliasIdentificationVariable(); + $sourceQComp = $this->_queryComponents[$joinAssocPathExpr->getIdentificationVariable()]; + $targetQComp = $this->_queryComponents[$joinedDqlAlias]; + $targetTableName = $targetQComp['metadata']->getTableName(); - $targetTableAlias = $this->_dqlToSqlAliasMap[$join->getAliasIdentificationVariable()]; - $sourceTableAlias = $this->_dqlToSqlAliasMap[$joinAssocPathExpr->getIdentificationVariable()]; + $targetTableAlias = $this->getSqlTableAlias($targetTableName); + $sourceTableAlias = $this->getSqlTableAlias($sourceQComp['metadata']->getTableName()); $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON '; @@ -238,63 +279,87 @@ class SqlWalker $sql = ''; $expr = $selectExpression->getExpression(); if ($expr instanceof AST\StateFieldPathExpression) { - $pathExpression = $expr; - if ($pathExpression->isSimpleStateFieldPathExpression()) { - $parts = $pathExpression->getParts(); + if ($expr->isSimpleStateFieldPathExpression()) { + $parts = $expr->getParts(); $numParts = count($parts); $dqlAlias = $parts[0]; $fieldName = $parts[$numParts-1]; - $qComp = $this->_parserResult->getQueryComponent($dqlAlias); + $qComp = $this->_queryComponents[$dqlAlias]; $class = $qComp['metadata']; + if ( ! isset($this->_selectedClasses[$dqlAlias])) { + $this->_selectedClasses[$dqlAlias] = $class; + } + if ($numParts > 2) { for ($i = 1; $i < $numParts-1; ++$i) { //TODO } } - $sqlTableAlias = $this->_dqlToSqlAliasMap[$dqlAlias]; - $sql .= $sqlTableAlias . '.' . $class->getColumnName($fieldName) . - ' AS ' . $sqlTableAlias . '__' . $class->getColumnName($fieldName); - } else if ($pathExpression->isSimpleStateFieldAssociationPathExpression()) { + $sqlTableAlias = $this->getSqlTableAlias($class->getTableName()); + $columnName = $class->getColumnName($fieldName); + $columnAlias = $this->getSqlColumnAlias($columnName); + $sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias; + + // Register column in ResultSetMapping + $this->_resultSetMapping->addFieldResult($dqlAlias, $columnAlias, $fieldName); + + } else if ($expr->isSimpleStateFieldAssociationPathExpression()) { throw DoctrineException::updateMe("Not yet implemented."); } else { throw DoctrineException::updateMe("Encountered invalid PathExpression during SQL construction."); } - } - else if ($expr instanceof AST\AggregateExpression) { - $aggExpr = $expr; + } else if ($expr instanceof AST\AggregateExpression) { if ( ! $selectExpression->getFieldIdentificationVariable()) { - $alias = $this->_scalarAliasCounter++; + $resultAlias = $this->_scalarResultCounter++; } else { - $alias = $selectExpression->getFieldIdentificationVariable(); + $resultAlias = $selectExpression->getFieldIdentificationVariable(); } - $sql .= $this->walkAggregateExpression($aggExpr) . ' AS dctrn__' . $alias; - } - else if ($expr instanceof AST\Subselect) { + $columnAlias = 'sclr' . $this->_aliasCounter++; + $sql .= $this->walkAggregateExpression($expr) . ' AS ' . $columnAlias; + $this->_resultSetMapping->addScalarResult($columnAlias, $resultAlias); + } else if ($expr instanceof AST\Subselect) { $sql .= $this->walkSubselect($expr); } else if ($expr instanceof AST\Functions\FunctionNode) { if ( ! $selectExpression->getFieldIdentificationVariable()) { - $alias = $this->_scalarAliasCounter++; + $resultAlias = $this->_scalarResultCounter++; } else { - $alias = $selectExpression->getFieldIdentificationVariable(); + $resultAlias = $selectExpression->getFieldIdentificationVariable(); } - $sql .= $this->walkFunction($expr) . ' AS dctrn__' . $alias; + $columnAlias = 'sclr' . $this->_aliasCounter++; + $sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias; + $this->_resultSetMapping->addScalarResult($columnAlias, $resultAlias); } else { $dqlAlias = $expr; - $queryComp = $this->_parserResult->getQueryComponent($dqlAlias); + $queryComp = $this->_queryComponents[$dqlAlias]; $class = $queryComp['metadata']; - $sqlTableAlias = $this->_dqlToSqlAliasMap[$dqlAlias]; + if ( ! isset($this->_selectedClasses[$dqlAlias])) { + $this->_selectedClasses[$dqlAlias] = $class; + } + + $sqlTableAlias = $this->getSqlTableAlias($class->getTableName()); + + $fieldMappings = $class->getFieldMappings(); + foreach ($class->getSubclasses() as $subclassName) { + $fieldMappings = array_merge( + $fieldMappings, + $this->_em->getClassMetadata($subclassName)->getFieldMappings() + ); + } + $beginning = true; - foreach ($class->getFieldMappings() as $fieldName => $fieldMapping) { + foreach ($fieldMappings as $fieldName => $fieldMapping) { if ($beginning) { $beginning = false; } else { $sql .= ', '; } - $sql .= $sqlTableAlias . '.' . $fieldMapping['columnName'] . - ' AS ' . $sqlTableAlias . '__' . $fieldMapping['columnName']; + $columnAlias = $this->getSqlColumnAlias($fieldMapping['columnName']); + $sql .= $sqlTableAlias . '.' . $fieldMapping['columnName'] . ' AS ' . $columnAlias; + + $this->_resultSetMapping->addFieldResult($dqlAlias, $columnAlias, $fieldName); } } return $sql; @@ -346,7 +411,7 @@ class SqlWalker $firstIdentificationVarDecl = $identificationVarDecls[0]; $rangeDecl = $firstIdentificationVarDecl->getRangeVariableDeclaration(); $sql .= $rangeDecl->getClassMetadata()->getTableName() . ' ' - . $this->_dqlToSqlAliasMap[$rangeDecl->getAliasIdentificationVariable()]; + . $this->getSqlTableAlias($rangeDecl->getClassMetadata()->getTableName()); foreach ($firstIdentificationVarDecl->getJoinVariableDeclarations() as $joinVarDecl) { $sql .= $this->walkJoinVariableDeclaration($joinVarDecl); @@ -411,12 +476,12 @@ class SqlWalker $dqlAlias = $parts[0]; $fieldName = $parts[1]; - $qComp = $this->_parserResult->getQueryComponent($dqlAlias); + $qComp = $this->_queryComponents[$dqlAlias]; $columnName = $qComp['metadata']->getColumnName($fieldName); $sql .= $aggExpression->getFunctionName() . '('; if ($aggExpression->isDistinct()) $sql .= 'DISTINCT '; - $sql .= $this->_dqlToSqlAliasMap[$dqlAlias] . '.' . $columnName; + $sql .= $this->getSqlTableAlias($qComp['metadata']->getTableName()) . '.' . $columnName; $sql .= ')'; return $sql; } @@ -444,9 +509,9 @@ class SqlWalker { //TODO: support general SingleValuedPathExpression, not just state field $parts = $pathExpr->getParts(); - $qComp = $this->_parserResult->getQueryComponent($parts[0]); + $qComp = $this->_queryComponents[$parts[0]]; $columnName = $qComp['metadata']->getColumnName($parts[1]); - return $this->_dqlToSqlAliasMap[$parts[0]] . '.' . $columnName; + return $this->getSqlTableAlias($qComp['metadata']->getTableName()) . '.' . $columnName; } /** @@ -487,7 +552,7 @@ class SqlWalker $class = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName()); $sql .= $class->getTableName(); if ($deleteClause->getAliasIdentificationVariable()) { - $sql .= ' ' . $this->_dqlToSqlAliasMap[$deleteClause->getAliasIdentificationVariable()]; + $sql .= ' ' . $this->getSqlTableAlias($class->getTableName()); } return $sql; } @@ -504,7 +569,7 @@ class SqlWalker $class = $this->_em->getClassMetadata($updateClause->getAbstractSchemaName()); $sql .= $class->getTableName(); if ($updateClause->getAliasIdentificationVariable()) { - $sql .= ' ' . $this->_dqlToSqlAliasMap[$updateClause->getAliasIdentificationVariable()]; + $sql .= ' ' . $this->getSqlTableAlias($class->getTableName()); } $sql .= ' SET ' . implode(', ', array_map(array($this, 'walkUpdateItem'), $updateClause->getUpdateItems())); @@ -524,9 +589,9 @@ class SqlWalker $dqlAlias = $updateItem->getIdentificationVariable() ? $updateItem->getIdentificationVariable() : $this->_parserResult->getDefaultQueryComponentAlias(); - $qComp = $this->_parserResult->getQueryComponent($dqlAlias); + $qComp = $this->_queryComponents[$dqlAlias]; - $sql .= $this->_dqlToSqlAliasMap[$dqlAlias] . '.' + $sql .= $this->getSqlTableAlias($qComp['metadata']->getTableName()) . '.' . $qComp['metadata']->getColumnName($updateItem->getField()) . ' = '; @@ -854,7 +919,7 @@ class SqlWalker $numParts = count($parts); $dqlAlias = $parts[0]; $fieldName = $parts[$numParts-1]; - $qComp = $this->_parserResult->getQueryComponent($dqlAlias); + $qComp = $this->_queryComponents[$dqlAlias]; $class = $qComp['metadata']; if ($numParts > 2) { @@ -863,7 +928,7 @@ class SqlWalker } } - $sqlTableAlias = $this->_dqlToSqlAliasMap[$dqlAlias]; + $sqlTableAlias = $this->getSqlTableAlias($class->getTableName()); $sql .= $sqlTableAlias . '.' . $class->getColumnName($fieldName); } else if ($pathExpr->isSimpleStateFieldAssociationPathExpression()) { throw DoctrineException::updateMe("Not yet implemented."); @@ -876,11 +941,19 @@ class SqlWalker /** * Generates a unique, short SQL table alias. * - * @param string $tableName Table name. + * @param string $dqlAlias The DQL alias. * @return string Generated table alias. */ - public function generateSqlTableAlias($tableName) + public function getSqlTableAlias($tableName) { - return strtolower(substr($tableName, 0, 1)) . $this->_tableAliasCounter++; + if ( ! isset($this->_dqlToSqlAliasMap[$tableName])) { + $this->_dqlToSqlAliasMap[$tableName] = strtolower(substr($tableName, 0, 1)) . $this->_tableAliasCounter++ . '_'; + } + return $this->_dqlToSqlAliasMap[$tableName]; + } + + public function getSqlColumnAlias($columnName) + { + return $columnName . $this->_aliasCounter++; } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php index 089211c97..1952394a4 100644 --- a/lib/Doctrine/ORM/Tools/SchemaTool.php +++ b/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -21,6 +21,7 @@ namespace Doctrine\ORM\Tools; +use Doctrine\DBAL\Types\Type; use Doctrine\ORM\EntityManager; /** @@ -76,30 +77,19 @@ class SchemaTool */ public function getCreateSchemaSql(array $classes) { + $processedClasses = array(); $sql = array(); $foreignKeyConstraints = array(); // First we create the tables foreach ($classes as $class) { - $columns = array(); // table columns - $options = array(); // table options - - foreach ($class->getFieldMappings() as $fieldName => $mapping) { - $column = array(); - $column['name'] = $mapping['columnName']; - $column['type'] = $mapping['type']; - $column['length'] = $mapping['length']; - $column['notnull'] = ! $mapping['nullable']; - if ($class->isIdentifier($fieldName)) { - $column['primary'] = true; - $options['primary'][] = $mapping['columnName']; - if ($class->isIdGeneratorIdentity()) { - $column['autoincrement'] = true; - } - } - $columns[$mapping['columnName']] = $column; + if (isset($processedClasses[$class->getClassName()])) { + continue; } + $columns = $this->_gatherColumns($class); // table columns + $options = array(); // table options + foreach ($class->getAssociationMappings() as $mapping) { $foreignClass = $this->_em->getClassMetadata($mapping->getTargetEntityName()); if ($mapping->isOneToOne() && $mapping->isOwningSide()) { @@ -165,7 +155,28 @@ class SchemaTool } } + if ($class->isInheritanceTypeSingleTable()) { + // Add the discriminator column + $discrColumnDef = $this->_getDiscriminatorColumnDefinition($class); + $columns[$discrColumnDef['name']] = $discrColumnDef; + + // Aggregate all the information from all classes in the hierarchy + foreach ($class->getParentClasses() as $parentClassName) { + // Parent class information is already contained in this class + $processedClasses[$parentClassName] = true; + } + foreach ($class->getSubclasses() as $subClassName) { + $columns = array_merge($columns, $this->_gatherColumns($this->_em->getClassMetadata($subClassName))); + $processedClasses[$subClassName] = true; + } + } else if ($class->isInheritanceTypeJoined()) { + //TODO + } else if ($class->isInheritanceTypeTablePerClass()) { + //TODO + } + $sql = array_merge($sql, $this->_platform->getCreateTableSql($class->getTableName(), $columns, $options)); + $processedClasses[$class->getClassName()] = true; } // Now create the foreign key constraints @@ -178,6 +189,38 @@ class SchemaTool return $sql; } + private function _getDiscriminatorColumnDefinition($class) + { + $discrColumn = $class->getDiscriminatorColumn(); + return array( + 'name' => $discrColumn['name'], + 'type' => Type::getType($discrColumn['type']), + 'length' => $discrColumn['length'], + 'notnull' => true + ); + } + + private function _gatherColumns($class) + { + $columns = array(); + foreach ($class->getFieldMappings() as $fieldName => $mapping) { + $column = array(); + $column['name'] = $mapping['columnName']; + $column['type'] = $mapping['type']; + $column['length'] = $mapping['length']; + $column['notnull'] = ! $mapping['nullable']; + if ($class->isIdentifier($fieldName)) { + $column['primary'] = true; + $options['primary'][] = $mapping['columnName']; + if ($class->isIdGeneratorIdentity()) { + $column['autoincrement'] = true; + } + } + $columns[$mapping['columnName']] = $column; + } + return $columns; + } + public function dropSchema(array $classes) { //TODO diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index c7fcbe6c5..25fee1a97 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -21,7 +21,9 @@ namespace Doctrine\ORM; +use Doctrine\Common\Collections\Collection; use Doctrine\Common\DoctrineException; +use Doctrine\Common\PropertyChangedListener; use Doctrine\ORM\Internal\CommitOrderCalculator; use Doctrine\ORM\Internal\CommitOrderNode; use Doctrine\ORM\PersistentCollection; @@ -40,7 +42,7 @@ use Doctrine\ORM\EntityManager; * @version $Revision$ * @author Roman Borschel */ -class UnitOfWork +class UnitOfWork implements PropertyChangedListener { /** * An Entity is in managed state when it has a primary key/identifier (and @@ -217,7 +219,8 @@ class UnitOfWork */ public function commit() { - // Compute changes done since last commit + // Compute changes done since last commit. + // This populates _entityUpdates and _collectionUpdates. $this->computeChangeSets(); if (empty($this->_entityInsertions) && @@ -315,12 +318,25 @@ class UnitOfWork foreach ($entitySet as $className => $entities) { $class = $this->_em->getClassMetadata($className); if ( ! $class->isInheritanceTypeNone() && count($entities) > 0) { - $class = $this->_em->getClassMetadata(get_class($entities[0])); + $class = $this->_em->getClassMetadata(get_class($entities[key($entities)])); } + + /* + if ($class->isChangeTrackingNotify()) { + continue; + } + $entitiesToProcess = $class->isChangeTrackingDeferredExplicit() ? + $this->_scheduledForDirtyCheck[$className] : $entities; + */ + foreach ($entities as $entity) { $oid = spl_object_hash($entity); $state = $this->getEntityState($entity); + if ($state == self::STATE_MANAGED && ($entity instanceof \Doctrine\Common\NotifyPropertyChanged)) { + continue; // entity notifies us, no need to calculate changes + } + // Look for changes in the entity itself by comparing against the // original data we have. if ($state == self::STATE_MANAGED || $state == self::STATE_NEW) { @@ -596,7 +612,7 @@ class UnitOfWork } /** - * Register a new entity. + * Registers a new entity. * * @todo Rename to scheduleForInsert(). */ @@ -782,7 +798,7 @@ class UnitOfWork public function addToIdentityMap($entity) { $classMetadata = $this->_em->getClassMetadata(get_class($entity)); - $idHash = $this->getIdentifierHash($this->_entityIdentifiers[spl_object_hash($entity)]); + $idHash = implode(' ', $this->_entityIdentifiers[spl_object_hash($entity)]); if ($idHash === '') { throw DoctrineException::updateMe("Entity with oid '" . spl_object_hash($entity) . "' has no identity and therefore can't be added to the identity map."); @@ -792,6 +808,9 @@ class UnitOfWork return false; } $this->_identityMap[$className][$idHash] = $entity; + if ($entity instanceof \Doctrine\Common\NotifyPropertyChanged) { + $entity->addPropertyChangedListener($this); + } return true; } @@ -825,7 +844,7 @@ class UnitOfWork { $oid = spl_object_hash($entity); $classMetadata = $this->_em->getClassMetadata(get_class($entity)); - $idHash = $this->getIdentifierHash($this->_entityIdentifiers[$oid]); + $idHash = implode(' ', $this->_entityIdentifiers[$oid]); if ($idHash === '') { throw DoctrineException::updateMe("Entity with oid '" . spl_object_hash($entity) . "' has no identity and therefore can't be removed from the identity map."); @@ -868,22 +887,6 @@ class UnitOfWork return false; } - /** - * Gets the identifier hash for a set of identifier values. - * The hash is just a concatenation of the identifier values. - * The identifiers are concatenated with a space. - * - * Note that this method always returns a string. If the given array is - * empty, an empty string is returned. - * - * @param array $id - * @return string The hash. - */ - public function getIdentifierHash(array $id) - { - return implode(' ', $id); - } - /** * Checks whether an entity is registered in the identity map of the * UnitOfWork. @@ -898,7 +901,7 @@ class UnitOfWork return false; } $classMetadata = $this->_em->getClassMetadata(get_class($entity)); - $idHash = $this->getIdentifierHash($this->_entityIdentifiers[$oid]); + $idHash = implode(' ', $this->_entityIdentifiers[$oid]); if ($idHash === '') { return false; } @@ -968,11 +971,15 @@ class UnitOfWork switch ($this->getEntityState($entity)) { case self::STATE_MANAGED: // nothing to do, except if automatic dirty checking is disabled + /*if ($class->isChangeTrackingDeferredExplicit()) { + $this->scheduleForDirtyCheck($entity); + }*/ if ( ! $this->_em->getConfiguration()->getAutomaticDirtyChecking()) { $this->scheduleForDirtyCheck($entity); } break; case self::STATE_NEW: + //TODO: Better defer insert for post-insert ID generators also. $idGen = $class->getIdGenerator(); if ($idGen->isPostInsertGenerator()) { $insertNow[$oid] = $entity; @@ -986,6 +993,8 @@ class UnitOfWork $this->_entityIdentifiers[$oid] = $idValue; } } + //TODO: Calculate changeSet now instead of later to allow some optimizations + // in calculateChangeSets() (ie no need to consider NEW objects) ? $this->registerNew($entity); break; case self::STATE_DETACHED: @@ -1002,7 +1011,6 @@ class UnitOfWork } break; default: - //TODO: throw UnitOfWorkException::invalidEntityState() throw DoctrineException::updateMe("Encountered invalid entity state."); } $this->_cascadeSave($entity, $visited, $insertNow); @@ -1021,11 +1029,12 @@ class UnitOfWork /** * Deletes an entity as part of the current unit of work. + * * This method is internally called during delete() cascades as it tracks * the already visited entities to prevent infinite recursions. * - * @param object $entity - * @param array $visited + * @param object $entity The entity to delete. + * @param array $visited The map of the already visited entities. */ private function _doDelete($entity, array &$visited) { @@ -1067,7 +1076,7 @@ class UnitOfWork } $relatedEntities = $class->getReflectionProperty($assocMapping->getSourceFieldName()) ->getValue($entity); - if (($relatedEntities instanceof \Doctrine\Common\Collections\Collection || is_array($relatedEntities)) + if (($relatedEntities instanceof Collection || is_array($relatedEntities)) && count($relatedEntities) > 0) { foreach ($relatedEntities as $relatedEntity) { $this->_doSave($relatedEntity, $visited, $insertNow); @@ -1092,7 +1101,7 @@ class UnitOfWork } $relatedEntities = $class->getReflectionProperty($assocMapping->getSourceFieldName()) ->getValue($entity); - if ($relatedEntities instanceof \Doctrine\Common\Collections\Collection || is_array($relatedEntities) + if ($relatedEntities instanceof Collection || is_array($relatedEntities) && count($relatedEntities) > 0) { foreach ($relatedEntities as $relatedEntity) { $this->_doDelete($relatedEntity, $visited); @@ -1164,7 +1173,15 @@ class UnitOfWork */ public function createEntity($className, array $data, $query = null) { - $className = $this->_inferCorrectClassName($data, $className); + // Infer the correct class to instantiate + $class = $this->_em->getClassMetadata($className); + $discCol = $class->getDiscriminatorColumn(); + if ($discCol) { + $discMap = $class->getDiscriminatorMap(); + if (isset($data[$discCol['name']], $discMap[$data[$discCol['name']]])) { + $className = $discMap[$data[$discCol['name']]]; + } + } $class = $this->_em->getClassMetadata($className); $id = array(); @@ -1173,7 +1190,7 @@ class UnitOfWork foreach ($identifierFieldNames as $fieldName) { $id[] = $data[$fieldName]; } - $idHash = $this->getIdentifierHash($id); + $idHash = implode(' ', $id); } else { $id = array($data[$class->getSingleIdentifierFieldName()]); $idHash = $id[0]; @@ -1229,30 +1246,6 @@ class UnitOfWork } } - /** - * Check the dataset for a discriminator column to determine the correct - * class to instantiate. If no discriminator column is found, the given - * classname will be returned. - * - * @param array $data - * @param string $className - * @return string The name of the class to instantiate. - */ - private function _inferCorrectClassName(array $data, $className) - { - $class = $this->_em->getClassMetadata($className); - $discCol = $class->getDiscriminatorColumn(); - if ( ! $discCol) { - return $className; - } - $discMap = $class->getDiscriminatorMap(); - if (isset($data[$discCol['name']], $discMap[$data[$discCol['name']]])) { - return $discMap[$data[$discCol['name']]]; - } else { - return $className; - } - } - /** * Gets the identity map of the UnitOfWork. * @@ -1313,19 +1306,34 @@ class UnitOfWork */ public function tryGetById($id, $rootClassName) { - $idHash = $this->getIdentifierHash((array)$id); + $idHash = implode(' ', (array)$id); if (isset($this->_identityMap[$rootClassName][$idHash])) { return $this->_identityMap[$rootClassName][$idHash]; } return false; } + /** + * Schedules an entity for dirty-checking at commit-time. + * + * @param object $entity The entity to schedule for dirty-checking. + */ public function scheduleForDirtyCheck($entity) { $rootClassName = $this->_em->getClassMetadata(get_class($entity))->getRootClassName(); $this->_scheduledForDirtyCheck[$rootClassName] = $entity; } + /** + * Checks whether the UnitOfWork has any pending insertions. + * + * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise. + */ + public function hasPendingInsertions() + { + return ! empty($this->_entityInsertions); + } + /** * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the * number of entities in the identity map. @@ -1349,10 +1357,14 @@ class UnitOfWork { if ( ! isset($this->_persisters[$entityName])) { $class = $this->_em->getClassMetadata($entityName); - if ($class->isInheritanceTypeJoined()) { + if ($class->isInheritanceTypeNone()) { + $persister = new Persisters\StandardEntityPersister($this->_em, $class); + } else if ($class->isInheritanceTypeSingleTable()) { + $persister = new Persisters\SingleTablePersister($this->_em, $class); + } else if ($class->isInheritanceTypeJoined()) { $persister = new Persisters\JoinedSubclassPersister($this->_em, $class); } else { - $persister = new Persisters\StandardEntityPersister($this->_em, $class); + $persister = new Persisters\UnionSubclassPersister($this->_em, $class); } $this->_persisters[$entityName] = $persister; } @@ -1378,4 +1390,36 @@ class UnitOfWork } return $this->_collectionPersisters[$type]; } + + /* PropertyChangedListener implementation */ + + /** + * Notifies this UnitOfWork of a property change in an entity. + * + * @param object $entity The entity that owns the property. + * @param string $propertyName The name of the property that changed. + * @param mixed $oldValue The old value of the property. + * @param mixed $newValue The new value of the property. + */ + public function propertyChanged($entity, $propertyName, $oldValue, $newValue) + { + $oid = spl_object_hash($entity); + $class = $this->_em->getClassMetadata(get_class($entity)); + + $this->_entityChangeSets[$oid][$propertyName] = array($oldValue => $newValue); + + if ($class->hasAssociation($propertyName)) { + $assoc = $class->getAssociationMapping($name); + if ($assoc->isOneToOne() && $assoc->isOwningSide()) { + $this->_entityUpdates[$oid] = $entity; + } else if ($oldValue instanceof PersistentCollection) { + // A PersistentCollection was de-referenced, so delete it. + if ( ! in_array($orgValue, $this->_collectionDeletions, true)) { + $this->_collectionDeletions[] = $orgValue; + } + } + } else { + $this->_entityUpdates[$oid] = $entity; + } + } } \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/CMS/CmsUser.php b/tests/Doctrine/Tests/Models/CMS/CmsUser.php index fe5e472e9..aa6a1a659 100644 --- a/tests/Doctrine/Tests/Models/CMS/CmsUser.php +++ b/tests/Doctrine/Tests/Models/CMS/CmsUser.php @@ -56,6 +56,11 @@ class CmsUser $phone->user = $this; } + public function addArticle(CmsArticle $article) { + $this->articles[] = $article; + $article->user = $this; + } + public function removePhonenumber($index) { if (isset($this->phonenumbers[$index])) { $ph = $this->phonenumbers[$index]; diff --git a/tests/Doctrine/Tests/ORM/EntityPersisterTest.php b/tests/Doctrine/Tests/ORM/EntityPersisterTest.php index 01f773e29..5f6fe2421 100644 --- a/tests/Doctrine/Tests/ORM/EntityPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/EntityPersisterTest.php @@ -32,7 +32,7 @@ class EntityPersisterTest extends \Doctrine\Tests\OrmTestCase public function testSimpleInsert() { - $userPersister = new \Doctrine\ORM\Persisters\StandardEntityPersister( + $userPersister = new \Doctrine\ORM\Persisters\SingleTablePersister( $this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser")); $avatarPersister = new \Doctrine\ORM\Persisters\StandardEntityPersister( $this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumAvatar")); diff --git a/tests/Doctrine/Tests/ORM/Functional/QueryTest.php b/tests/Doctrine/Tests/ORM/Functional/QueryTest.php index 00182523d..4957704fa 100644 --- a/tests/Doctrine/Tests/ORM/Functional/QueryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/QueryTest.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\ORM\Functional; use Doctrine\Tests\Models\CMS\CmsUser; +use Doctrine\Tests\Models\CMS\CmsArticle; require_once __DIR__ . '/../../TestInit.php'; @@ -59,5 +60,38 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('GUILHERME', $query->getSingleScalarResult()); } + public function testJoinQueries() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $article1 = new CmsArticle; + $article1->topic = "Doctrine 2"; + $article1->text = "This is an introduction to Doctrine 2."; + $user->addArticle($article1); + + $article2 = new CmsArticle; + $article2->topic = "Symfony 2"; + $article2->text = "This is an introduction to Symfony 2."; + $user->addArticle($article2); + + $this->_em->save($user); + $this->_em->save($article1); + $this->_em->save($article2); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u join u.articles a"); + $users = $query->getResultList(); + $this->assertEquals(1, count($users)); + $this->assertTrue($users[0] instanceof CmsUser); + $this->assertEquals(2, count($users[0]->articles)); + $this->assertEquals('Doctrine 2', $users[0]->articles[0]->topic); + $this->assertEquals('Symfony 2', $users[0]->articles[1]->topic); + } + } diff --git a/tests/Doctrine/Tests/ORM/Hydration/AllTests.php b/tests/Doctrine/Tests/ORM/Hydration/AllTests.php index be065cfab..76a9cbcb1 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/AllTests.php +++ b/tests/Doctrine/Tests/ORM/Hydration/AllTests.php @@ -24,6 +24,7 @@ class AllTests $suite->addTestSuite('Doctrine\Tests\ORM\Hydration\ArrayHydratorTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Hydration\ScalarHydratorTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Hydration\SingleScalarHydratorTest'); + $suite->addTestSuite('Doctrine\Tests\ORM\Hydration\ResultSetMappingTest'); return $suite; } diff --git a/tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php b/tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php index edd7687f1..5f4c18a43 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\ORM\Hydration; use Doctrine\Tests\Mocks\HydratorMockStatement; +use Doctrine\ORM\Query\ResultSetMapping; require_once __DIR__ . '/../../TestInit.php'; @@ -13,20 +14,10 @@ class ArrayHydratorTest extends HydrationTest */ public function testNewHydrationSimpleEntityQuery() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'u' => 'u' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); // Faked result set $resultSet = array( @@ -44,8 +35,7 @@ class ArrayHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -55,6 +45,53 @@ class ArrayHydratorTest extends HydrationTest $this->assertEquals('jwage', $result[1]['name']); } + /** + * + */ + public function testNewHydrationSimpleMultipleRootEntityQuery() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), 'a'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); + + $this->assertEquals(4, count($result)); + + $this->assertEquals(1, $result[0]['id']); + $this->assertEquals('romanb', $result[0]['name']); + $this->assertEquals(1, $result[1]['id']); + $this->assertEquals('Cool things.', $result[1]['topic']); + $this->assertEquals(2, $result[2]['id']); + $this->assertEquals('jwage', $result[2]['name']); + $this->assertEquals(2, $result[3]['id']); + $this->assertEquals('Cool things II.', $result[3]['topic']); + } + /** * select u.id, u.status, p.phonenumber, upper(u.name) nameUpper from User u * join u.phonenumbers p @@ -64,28 +101,18 @@ class ArrayHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryFetchJoin() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); // Faked result set $resultSet = array( @@ -93,19 +120,19 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', ), array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', ), array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91' ) ); @@ -113,8 +140,7 @@ class ArrayHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -142,28 +168,11 @@ class ArrayHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryNormalJoin() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'numPhones'); // Faked result set $resultSet = array( @@ -171,20 +180,19 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__numPhones' => '2', + 'sclr0' => '2', ), array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__numPhones' => '1', + 'sclr0' => '1', ) ); $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -205,28 +213,20 @@ class ArrayHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryFetchJoinCustomIndex() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => 'id' - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => 'phonenumber' - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addIndexBy('u', 'id'); + $rsm->addIndexBy('p', 'phonenumber'); // Faked result set $resultSet = array( @@ -234,19 +234,19 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', ), array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', ), array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91' ) ); @@ -255,8 +255,7 @@ class ArrayHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -289,35 +288,26 @@ class ArrayHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryMultipleFetchJoin() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ), - 'a' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles'), - 'map' => null - ), - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p', - 'a' => 'a' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') + ); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), + 'a', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles') + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); // Faked result set $resultSet = array( @@ -325,7 +315,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', 'a__id' => '1', 'a__topic' => 'Getting things done!' @@ -333,7 +323,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', 'a__id' => '1', 'a__topic' => 'Getting things done!' @@ -341,7 +331,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', 'a__id' => '2', 'a__topic' => 'ZendCon' @@ -349,7 +339,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', 'a__id' => '2', 'a__topic' => 'ZendCon' @@ -357,7 +347,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91', 'a__id' => '3', 'a__topic' => 'LINQ' @@ -365,7 +355,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91', 'a__id' => '4', 'a__topic' => 'PHP6' @@ -375,8 +365,7 @@ class ArrayHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -418,42 +407,35 @@ class ArrayHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryMultipleDeepMixedFetchJoin() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ), - 'a' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles'), - 'map' => null - ), - 'c' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsComment'), - 'parent' => 'a', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle')->getAssociationMapping('comments'), - 'map' => null - ), - ); - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p', - 'a' => 'a', - 'c' => 'c' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') + ); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), + 'a', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles') + ); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsComment'), + 'c', + 'a', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle')->getAssociationMapping('comments') + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__topic', 'topic'); // Faked result set $resultSet = array( @@ -461,7 +443,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', 'a__id' => '1', 'a__topic' => 'Getting things done!', @@ -471,7 +453,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', 'a__id' => '1', 'a__topic' => 'Getting things done!', @@ -481,7 +463,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', 'a__id' => '2', 'a__topic' => 'ZendCon', @@ -491,7 +473,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', 'a__id' => '2', 'a__topic' => 'ZendCon', @@ -501,7 +483,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91', 'a__id' => '3', 'a__topic' => 'LINQ', @@ -511,7 +493,7 @@ class ArrayHydratorTest extends HydrationTest array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91', 'a__id' => '4', 'a__topic' => 'PHP6', @@ -523,8 +505,7 @@ class ArrayHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -584,27 +565,19 @@ class ArrayHydratorTest extends HydrationTest */ public function testNewHydrationEntityQueryCustomResultSetOrder() { - // Faked query components - $queryComponents = array( - 'c' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'b' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumBoard'), - 'parent' => 'c', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory')->getAssociationMapping('boards'), - 'map' => null - ), - ); - - // Faked table alias map - $tableAliasMap = array( - 'c' => 'c', - 'b' => 'b' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory'), 'c'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumBoard'), + 'b', + 'c', + $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory')->getAssociationMapping('boards') + ); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__position', 'position'); + $rsm->addFieldResult('c', 'c__name', 'name'); + $rsm->addFieldResult('b', 'b__id', 'id'); + $rsm->addFieldResult('b', 'b__position', 'position'); // Faked result set $resultSet = array( @@ -645,8 +618,7 @@ class ArrayHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -660,20 +632,10 @@ class ArrayHydratorTest extends HydrationTest public function testResultIteration() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'u' => 'u' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); // Faked result set $resultSet = array( @@ -691,8 +653,7 @@ class ArrayHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); - $iterableResult = $hydrator->iterate($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $iterableResult = $hydrator->iterate($stmt, $this->_createParserResult($rsm)); $rowNum = 0; while (($row = $iterableResult->next()) !== false) { diff --git a/tests/Doctrine/Tests/ORM/Hydration/HydrationTest.php b/tests/Doctrine/Tests/ORM/Hydration/HydrationTest.php index 0ed9226bf..035c655f7 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/HydrationTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/HydrationTest.php @@ -18,18 +18,12 @@ class HydrationTest extends \Doctrine\Tests\OrmTestCase } /** Helper method */ - protected function _createParserResult($queryComponents, $tableToClassAliasMap, $isMixedQuery = false) + protected function _createParserResult($resultSetMapping, $isMixedQuery = false) { - $parserResult = new ParserResult( - '', - array(/*queryComponent*/), - array(/*tableAliasMap*/) - ); - - //$parserResult = new \Doctrine\ORM\Query\ParserResult(); - $parserResult->setQueryComponents($queryComponents); - $parserResult->setDefaultQueryComponentAlias(key($queryComponents)); - $parserResult->setTableAliasMap($tableToClassAliasMap); + $parserResult = new ParserResult; + $parserResult->setResultSetMapping($resultSetMapping); + //$parserResult->setDefaultQueryComponentAlias(key($queryComponents)); + //$parserResult->setTableAliasMap($tableToClassAliasMap); $parserResult->setMixedQuery($isMixedQuery); return $parserResult; } diff --git a/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php b/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php index 761abc854..d5712da98 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\ORM\Hydration; use Doctrine\Tests\Mocks\HydratorMockStatement; +use Doctrine\ORM\Query\ResultSetMapping; require_once __DIR__ . '/../../TestInit.php'; @@ -13,20 +14,10 @@ class ObjectHydratorTest extends HydrationTest */ public function testNewHydrationSimpleEntityQuery() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'u' => 'u' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); // Faked result set $resultSet = array( @@ -44,8 +35,7 @@ class ObjectHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); $this->assertEquals(2, count($result)); $this->assertTrue($result[0] instanceof \Doctrine\Tests\Models\CMS\CmsUser); @@ -56,6 +46,58 @@ class ObjectHydratorTest extends HydrationTest $this->assertEquals('jwage', $result[1]->name); } + /** + * Select u.id, u.name from \Doctrine\Tests\Models\CMS\CmsUser u + */ + public function testNewHydrationSimpleMultipleRootEntityQuery() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), 'a'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); + + $this->assertEquals(4, count($result)); + + $this->assertTrue($result[0] instanceof \Doctrine\Tests\Models\CMS\CmsUser); + $this->assertTrue($result[1] instanceof \Doctrine\Tests\Models\CMS\CmsArticle); + $this->assertTrue($result[2] instanceof \Doctrine\Tests\Models\CMS\CmsUser); + $this->assertTrue($result[3] instanceof \Doctrine\Tests\Models\CMS\CmsArticle); + + $this->assertEquals(1, $result[0]->id); + $this->assertEquals('romanb', $result[0]->name); + $this->assertEquals(1, $result[1]->id); + $this->assertEquals('Cool things.', $result[1]->topic); + $this->assertEquals(2, $result[2]->id); + $this->assertEquals('jwage', $result[2]->name); + $this->assertEquals(2, $result[3]->id); + $this->assertEquals('Cool things II.', $result[3]->topic); + } + /** * select u.id, u.status, p.phonenumber, upper(u.name) nameUpper from User u * join u.phonenumbers p @@ -65,28 +107,18 @@ class ObjectHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryFetchJoin() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); // Faked result set $resultSet = array( @@ -94,19 +126,19 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', ), array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', ), array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91' ) ); @@ -114,8 +146,7 @@ class ObjectHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -150,28 +181,11 @@ class ObjectHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryNormalJoin() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'numPhones'); // Faked result set $resultSet = array( @@ -179,20 +193,19 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__numPhones' => '2', + 'sclr0' => '2', ), array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__numPhones' => '1', + 'sclr0' => '1', ) ); $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -215,28 +228,20 @@ class ObjectHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryFetchJoinCustomIndex() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => 'id' - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => 'phonenumber' - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addIndexBy('u', 'id'); + $rsm->addIndexBy('p', 'phonenumber'); // Faked result set $resultSet = array( @@ -244,19 +249,19 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', ), array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', ), array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91' ) ); @@ -265,8 +270,7 @@ class ObjectHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -303,35 +307,26 @@ class ObjectHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryMultipleFetchJoin() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ), - 'a' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles'), - 'map' => null - ), - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p', - 'a' => 'a' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') + ); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), + 'a', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles') + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); // Faked result set $resultSet = array( @@ -339,7 +334,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', 'a__id' => '1', 'a__topic' => 'Getting things done!' @@ -347,7 +342,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', 'a__id' => '1', 'a__topic' => 'Getting things done!' @@ -355,7 +350,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', 'a__id' => '2', 'a__topic' => 'ZendCon' @@ -363,7 +358,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', 'a__id' => '2', 'a__topic' => 'ZendCon' @@ -371,7 +366,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91', 'a__id' => '3', 'a__topic' => 'LINQ' @@ -379,7 +374,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91', 'a__id' => '4', 'a__topic' => 'PHP6' @@ -389,8 +384,7 @@ class ObjectHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -428,42 +422,34 @@ class ObjectHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryMultipleDeepMixedFetchJoin() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ), - 'a' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles'), - 'map' => null - ), - 'c' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsComment'), - 'parent' => 'a', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle')->getAssociationMapping('comments'), - 'map' => null - ), - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p', - 'a' => 'a', - 'c' => 'c' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') + ); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), + 'a', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles') + ); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsComment'), + 'c', + 'a', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle')->getAssociationMapping('comments') + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__topic', 'topic'); // Faked result set $resultSet = array( @@ -471,7 +457,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', 'a__id' => '1', 'a__topic' => 'Getting things done!', @@ -481,7 +467,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', 'a__id' => '1', 'a__topic' => 'Getting things done!', @@ -491,7 +477,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', 'a__id' => '2', 'a__topic' => 'ZendCon', @@ -501,7 +487,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', 'a__id' => '2', 'a__topic' => 'ZendCon', @@ -511,7 +497,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91', 'a__id' => '3', 'a__topic' => 'LINQ', @@ -521,7 +507,7 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91', 'a__id' => '4', 'a__topic' => 'PHP6', @@ -533,8 +519,7 @@ class ObjectHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); $this->assertEquals(2, count($result)); $this->assertTrue(is_array($result)); @@ -588,27 +573,19 @@ class ObjectHydratorTest extends HydrationTest */ public function testNewHydrationEntityQueryCustomResultSetOrder() { - // Faked query components - $queryComponents = array( - 'c' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'b' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumBoard'), - 'parent' => 'c', - 'relation' => $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory')->getAssociationMapping('boards'), - 'map' => null - ), - ); - - // Faked table alias map - $tableAliasMap = array( - 'c' => 'c', - 'b' => 'b' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory'), 'c'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumBoard'), + 'b', + 'c', + $this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory')->getAssociationMapping('boards') + ); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__position', 'position'); + $rsm->addFieldResult('c', 'c__name', 'name'); + $rsm->addFieldResult('b', 'b__id', 'id'); + $rsm->addFieldResult('b', 'b__position', 'position'); // Faked result set $resultSet = array( @@ -649,8 +626,7 @@ class ObjectHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); $this->assertEquals(2, count($result)); $this->assertTrue($result[0] instanceof \Doctrine\Tests\Models\Forum\ForumCategory); @@ -666,20 +642,10 @@ class ObjectHydratorTest extends HydrationTest public function testResultIteration() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'u' => 'u' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); // Faked result set $resultSet = array( @@ -697,8 +663,7 @@ class ObjectHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $iterableResult = $hydrator->iterate($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $iterableResult = $hydrator->iterate($stmt, $this->_createParserResult($rsm)); $rowNum = 0; while (($row = $iterableResult->next()) !== false) { @@ -726,28 +691,18 @@ class ObjectHydratorTest extends HydrationTest */ public function testNewHydrationMixedQueryFetchJoinPerformance() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('\Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ), - 'p' => array( - 'metadata' => $this->_em->getClassMetadata('\Doctrine\Tests\Models\CMS\CmsPhonenumber'), - 'parent' => 'u', - 'relation' => $this->_em->getClassMetadata('\Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers'), - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'dctrn' => 'dctrn', - 'u' => 'u', - 'p' => 'p' + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addJoinedEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + 'p', + 'u', + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); // Faked result set $resultSet = array( @@ -755,19 +710,19 @@ class ObjectHydratorTest extends HydrationTest array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '42', ), array( 'u__id' => '1', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'ROMANB', + 'sclr0' => 'ROMANB', 'p__phonenumber' => '43', ), array( 'u__id' => '2', 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE', + 'sclr0' => 'JWAGE', 'p__phonenumber' => '91' ) ); @@ -776,7 +731,7 @@ class ObjectHydratorTest extends HydrationTest $resultSet[] = array( 'u__id' => $i, 'u__status' => 'developer', - 'dctrn__nameUpper' => 'JWAGE' . $i, + 'sclr0' => 'JWAGE' . $i, 'p__phonenumber' => '91' ); } @@ -784,7 +739,6 @@ class ObjectHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap, true)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true)); } } \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php b/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php new file mode 100644 index 000000000..f663b00ea --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php @@ -0,0 +1,61 @@ +_rsm = new ResultSetMapping; + $this->_em = $this->_getTestEntityManager(); + } + + /** + * For SQL: SELECT id, status, username, name FROM cms_users + */ + public function testBasicResultSetMapping() + { + $this->_rsm->addEntityResult( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), + 'u' + ); + $this->_rsm->addFieldResult('u', 'id', 'id'); + $this->_rsm->addFieldResult('u', 'status', 'status'); + $this->_rsm->addFieldResult('u', 'username', 'username'); + $this->_rsm->addFieldResult('u', 'name', 'name'); + + $this->assertFalse($this->_rsm->isScalarResult('id')); + $this->assertFalse($this->_rsm->isScalarResult('status')); + $this->assertFalse($this->_rsm->isScalarResult('username')); + $this->assertFalse($this->_rsm->isScalarResult('name')); + + $this->assertTrue($this->_rsm->getClass('u') instanceof ClassMetadata); + $class = $this->_rsm->getOwningClass('id'); + $this->assertTrue($class instanceof ClassMetadata); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $class->getClassName()); + + $this->assertEquals('u', $this->_rsm->getEntityAlias('id')); + $this->assertEquals('u', $this->_rsm->getEntityAlias('status')); + $this->assertEquals('u', $this->_rsm->getEntityAlias('username')); + $this->assertEquals('u', $this->_rsm->getEntityAlias('name')); + + $this->assertEquals('id', $this->_rsm->getFieldName('id')); + $this->assertEquals('status', $this->_rsm->getFieldName('status')); + $this->assertEquals('username', $this->_rsm->getFieldName('username')); + $this->assertEquals('name', $this->_rsm->getFieldName('name')); + } +} + diff --git a/tests/Doctrine/Tests/ORM/Hydration/ScalarHydratorTest.php b/tests/Doctrine/Tests/ORM/Hydration/ScalarHydratorTest.php index 3011ca362..2d2b22c96 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/ScalarHydratorTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/ScalarHydratorTest.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\ORM\Hydration; use Doctrine\Tests\Mocks\HydratorMockStatement; +use Doctrine\ORM\Query\ResultSetMapping; require_once __DIR__ . '/../../TestInit.php'; @@ -13,20 +14,10 @@ class ScalarHydratorTest extends HydrationTest */ public function testNewHydrationSimpleEntityQuery() { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'u' => 'u' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); // Faked result set $resultSet = array( @@ -44,8 +35,7 @@ class ScalarHydratorTest extends HydrationTest $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this->_em); - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); $this->assertTrue(is_array($result)); $this->assertEquals(2, count($result)); diff --git a/tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php b/tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php index da141d7ce..19d871d91 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\ORM\Hydration; use Doctrine\Tests\Mocks\HydratorMockStatement; +use Doctrine\ORM\Query\ResultSetMapping; require_once __DIR__ . '/../../TestInit.php'; @@ -53,36 +54,23 @@ class SingleScalarHydratorTest extends HydrationTest */ public function testHydrateSingleScalar($name, $resultSet) { - // Faked query components - $queryComponents = array( - 'u' => array( - 'metadata' => $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), - 'parent' => null, - 'relation' => null, - 'map' => null - ) - ); - - // Faked table alias map - $tableAliasMap = array( - 'u' => 'u' - ); + $rsm = new ResultSetMapping; + $rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\SingleScalarHydrator($this->_em); if ($name == 'result1') { - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); $this->assertEquals('romanb', $result); } else if ($name == 'result2') { - $result = $hydrator->hydrateAll($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm)); $this->assertEquals(1, $result); } else if ($name == 'result3' || $name == 'result4') { try { - $result = $hydrator->hydrateall($stmt, $this->_createParserResult( - $queryComponents, $tableAliasMap)); + $result = $hydrator->hydrateall($stmt, $this->_createParserResult($rsm)); $this->fail(); } catch (\Doctrine\ORM\Internal\Hydration\HydrationException $ex) {} } diff --git a/tests/Doctrine/Tests/ORM/Mapping/AllTests.php b/tests/Doctrine/Tests/ORM/Mapping/AllTests.php index a6616af11..50c6f92a9 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AllTests.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AllTests.php @@ -20,7 +20,7 @@ class AllTests $suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Orm Mapping'); $suite->addTestSuite('Doctrine\Tests\ORM\Mapping\ClassMetadataTest'); - $suite->addTestSuite('Doctrine\Tests\ORM\Mapping\ClassMetadataFactoryTest'); + //$suite->addTestSuite('Doctrine\Tests\ORM\Mapping\ClassMetadataFactoryTest'); return $suite; } diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php index 0eaafe9df..5375e2bb5 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php @@ -47,75 +47,6 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase $this->assertTrue($cm1->hasField('name')); $this->assertEquals('sequence', $cm1->getIdGeneratorType()); } - - public function testGetMetadataForClassInHierarchy() - { - $mockPlatform = new DatabasePlatformMock(); - $mockPlatform->setPrefersIdentityColumns(true); - $mockDriver = new MetadataDriverMock(); - - // Self-made metadata - $cm1 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity1'); - $cm1->setInheritanceType('singleTable'); - // Add a mapped field - $cm1->mapField(array('fieldName' => 'name', 'type' => 'varchar')); - // Add a mapped field - $cm1->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true)); - // and a mapped association - $cm1->mapOneToOne(array('fieldName' => 'other', 'targetEntity' => 'Other', 'mappedBy' => 'this')); - // and an id generator type - $cm1->setIdGeneratorType('auto'); - - $cm2 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity2'); - $cm3 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity3'); - - $cmf = new ClassMetadataFactoryTestSubject($mockDriver, $mockPlatform); - // Set self-made metadata - $cmf->setMetadataForClass('Doctrine\Tests\ORM\Mapping\TestEntity1', $cm1); - $cmf->setMetadataForClass('Doctrine\Tests\ORM\Mapping\TestEntity2', $cm2); - $cmf->setMetadataForClass('Doctrine\Tests\ORM\Mapping\TestEntity3', $cm3); - - // Prechecks - $this->assertEquals(array(), $cm1->getParentClasses()); - $this->assertEquals(array(), $cm2->getParentClasses()); - $this->assertEquals(array(), $cm3->getParentClasses()); - $this->assertEquals('none', $cm2->getInheritanceType()); - $this->assertEquals('none', $cm3->getInheritanceType()); - $this->assertFalse($cm2->hasField('name')); - $this->assertFalse($cm3->hasField('name')); - $this->assertEquals(1, count($cm1->getAssociationMappings())); - $this->assertEquals(0, count($cm2->getAssociationMappings())); - $this->assertEquals(0, count($cm3->getAssociationMappings())); - $this->assertEquals('none', $cm2->getIdGeneratorType()); - $this->assertEquals('none', $cm3->getIdGeneratorType()); - - // Go - $cm3 = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\TestEntity3'); - - // Metadata gathering should start at the root of the hierarchy, from there on downwards - $this->assertEquals(array('Doctrine\Tests\ORM\Mapping\TestEntity1', 'Doctrine\Tests\ORM\Mapping\TestEntity2', 'Doctrine\Tests\ORM\Mapping\TestEntity3'), $cmf->getRequestedClasses()); - // Parent classes should be assigned by factory - $this->assertEquals(array('Doctrine\Tests\ORM\Mapping\TestEntity2', 'Doctrine\Tests\ORM\Mapping\TestEntity1'), $cm3->getParentClasses()); - $this->assertEquals('Doctrine\Tests\ORM\Mapping\TestEntity1', $cm3->getRootClassName()); - $this->assertEquals('Doctrine\Tests\ORM\Mapping\TestEntity1', $cm2->getRootClassName()); - $this->assertEquals('Doctrine\Tests\ORM\Mapping\TestEntity1', $cm1->getRootClassName()); - // Inheritance type should be inherited to Entity2 - $this->assertEquals('singleTable', $cm2->getInheritanceType()); - $this->assertEquals('singleTable', $cm3->getInheritanceType()); - // Field mappings should be inherited - $this->assertTrue($cm2->hasField('name')); - $this->assertTrue($cm3->hasField('name')); - // Association mappings should be inherited - $this->assertEquals(1, count($cm2->getAssociationMappings())); - $this->assertEquals(1, count($cm3->getAssociationMappings())); - $this->assertTrue($cm2->hasAssociation('other')); - $this->assertTrue($cm3->hasAssociation('other')); - // Id generator 'auto' should have been resolved to 'identity' as preferred by our - // mock platform (see above). And it should be inherited. - $this->assertEquals('identity', $cm1->getIdGeneratorType()); - $this->assertEquals('identity', $cm2->getIdGeneratorType()); - $this->assertEquals('identity', $cm3->getIdGeneratorType()); - } } /* Test subject class with overriden factory method for mocking purposes */ @@ -144,15 +75,3 @@ class ClassMetadataFactoryTestSubject extends \Doctrine\ORM\Mapping\ClassMetadat return $this->_requestedClasses; } } - -/* Test classes */ - -class TestEntity1 -{ - protected $id; - protected $name; - protected $other; -} - -class TestEntity2 extends TestEntity1 {} -class TestEntity3 extends TestEntity2 {} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Query/AllTests.php b/tests/Doctrine/Tests/ORM/Query/AllTests.php index fc92c5f04..2e76d68d3 100644 --- a/tests/Doctrine/Tests/ORM/Query/AllTests.php +++ b/tests/Doctrine/Tests/ORM/Query/AllTests.php @@ -19,7 +19,7 @@ class AllTests { $suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Orm Query'); - $suite->addTestSuite('Doctrine\Tests\ORM\Query\IdentifierRecognitionTest'); + //$suite->addTestSuite('Doctrine\Tests\ORM\Query\IdentifierRecognitionTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Query\SelectSqlGenerationTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Query\LanguageRecognitionTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Query\LexerTest'); diff --git a/tests/Doctrine/Tests/ORM/Query/DeleteSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/DeleteSqlGenerationTest.php index d615c66f8..0d589cfe0 100644 --- a/tests/Doctrine/Tests/ORM/Query/DeleteSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/DeleteSqlGenerationTest.php @@ -60,11 +60,11 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u', - 'DELETE FROM cms_users c0' + 'DELETE FROM cms_users c0_' ); $this->assertSqlGeneration( 'DELETE FROM Doctrine\Tests\Models\CMS\CmsUser u', - 'DELETE FROM cms_users c0' + 'DELETE FROM cms_users c0_' ); } @@ -72,7 +72,7 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1', - 'DELETE FROM cms_users c0 WHERE c0.id = ?' + 'DELETE FROM cms_users c0_ WHERE c0_.id = ?' ); } @@ -80,12 +80,12 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ?1 OR u.name = ?2', - 'DELETE FROM cms_users c0 WHERE c0.username = ? OR c0.name = ?' + 'DELETE FROM cms_users c0_ WHERE c0_.username = ? OR c0_.name = ?' ); $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1 OR ( u.username = ?2 OR u.name = ?3)', - 'DELETE FROM cms_users c0 WHERE c0.id = ? OR (c0.username = ? OR c0.name = ?)' + 'DELETE FROM cms_users c0_ WHERE c0_.id = ? OR (c0_.username = ? OR c0_.name = ?)' ); //$this->assertSqlGeneration( @@ -98,7 +98,7 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "delete from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1", - "DELETE FROM cms_users c0 WHERE c0.username = ?" + "DELETE FROM cms_users c0_ WHERE c0_.username = ?" ); } @@ -106,7 +106,7 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ?1 AND u.name = ?2", - "DELETE FROM cms_users c0 WHERE c0.username = ? AND c0.name = ?" + "DELETE FROM cms_users c0_ WHERE c0_.username = ? AND c0_.name = ?" ); } @@ -114,17 +114,17 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT u.id != ?1", - "DELETE FROM cms_users c0 WHERE NOT c0.id <> ?" + "DELETE FROM cms_users c0_ WHERE NOT c0_.id <> ?" ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT ( u.id != ?1 )", - "DELETE FROM cms_users c0 WHERE NOT (c0.id <> ?)" + "DELETE FROM cms_users c0_ WHERE NOT (c0_.id <> ?)" ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT ( u.id != ?1 AND u.username = ?2 )", - "DELETE FROM cms_users c0 WHERE NOT (c0.id <> ? AND c0.username = ?)" + "DELETE FROM cms_users c0_ WHERE NOT (c0_.id <> ? AND c0_.username = ?)" ); } @@ -135,32 +135,32 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase // id = ? was already tested (see testDeleteWithWhere()) $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > ?1", - "DELETE FROM cms_users c0 WHERE c0.id > ?" + "DELETE FROM cms_users c0_ WHERE c0_.id > ?" ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id >= ?1", - "DELETE FROM cms_users c0 WHERE c0.id >= ?" + "DELETE FROM cms_users c0_ WHERE c0_.id >= ?" ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id < ?1", - "DELETE FROM cms_users c0 WHERE c0.id < ?" + "DELETE FROM cms_users c0_ WHERE c0_.id < ?" ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id <= ?1", - "DELETE FROM cms_users c0 WHERE c0.id <= ?" + "DELETE FROM cms_users c0_ WHERE c0_.id <= ?" ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id <> ?1", - "DELETE FROM cms_users c0 WHERE c0.id <> ?" + "DELETE FROM cms_users c0_ WHERE c0_.id <> ?" ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id != ?1", - "DELETE FROM cms_users c0 WHERE c0.id <> ?" + "DELETE FROM cms_users c0_ WHERE c0_.id <> ?" ); } @@ -168,12 +168,12 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT BETWEEN ?1 AND ?2", - "DELETE FROM cms_users c0 WHERE c0.id NOT BETWEEN ? AND ?" + "DELETE FROM cms_users c0_ WHERE c0_.id NOT BETWEEN ? AND ?" ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id BETWEEN ?1 AND ?2 AND u.username != ?3", - "DELETE FROM cms_users c0 WHERE c0.id BETWEEN ? AND ? AND c0.username <> ?" + "DELETE FROM cms_users c0_ WHERE c0_.id BETWEEN ? AND ? AND c0_.username <> ?" ); } @@ -182,12 +182,12 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase // "WHERE" Expression LikeExpression $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username NOT LIKE ?1', - 'DELETE FROM cms_users c0 WHERE c0.username NOT LIKE ?' + 'DELETE FROM cms_users c0_ WHERE c0_.username NOT LIKE ?' ); $this->assertSqlGeneration( "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username LIKE ?1 ESCAPE '\\'", - "DELETE FROM cms_users c0 WHERE c0.username LIKE ? ESCAPE '\\'" + "DELETE FROM cms_users c0_ WHERE c0_.username LIKE ? ESCAPE '\\'" ); } @@ -196,12 +196,12 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase // "WHERE" Expression NullComparisonExpression $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IS NULL', - 'DELETE FROM cms_users c0 WHERE c0.name IS NULL' + 'DELETE FROM cms_users c0_ WHERE c0_.name IS NULL' ); $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IS NOT NULL', - 'DELETE FROM cms_users c0 WHERE c0.name IS NOT NULL' + 'DELETE FROM cms_users c0_ WHERE c0_.name IS NOT NULL' ); } @@ -209,12 +209,12 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE 1 = 1', - 'DELETE FROM cms_users c0 WHERE 1 = 1' + 'DELETE FROM cms_users c0_ WHERE 1 = 1' ); $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE ?1 = 1', - 'DELETE FROM cms_users c0 WHERE ? = 1' + 'DELETE FROM cms_users c0_ WHERE ? = 1' ); } @@ -222,12 +222,12 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN ( ?1, ?2, ?3, ?4 )', - 'DELETE FROM cms_users c0 WHERE c0.id IN (?, ?, ?, ?)' + 'DELETE FROM cms_users c0_ WHERE c0_.id IN (?, ?, ?, ?)' ); $this->assertSqlGeneration( 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN ( ?1, ?2 )', - 'DELETE FROM cms_users c0 WHERE c0.id NOT IN (?, ?)' + 'DELETE FROM cms_users c0_ WHERE c0_.id NOT IN (?, ?)' ); } diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 3bf9aaa6c..403481fc4 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -30,12 +30,12 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', - 'SELECT c0.id AS c0__id, c0.status AS c0__status, c0.username AS c0__username, c0.name AS c0__name FROM cms_users c0' + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_' ); $this->assertSqlGeneration( 'SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u', - 'SELECT c0.id AS c0__id FROM cms_users c0' + 'SELECT c0_.id AS id0 FROM cms_users c0_' ); } @@ -43,7 +43,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u.username, u.name FROM Doctrine\Tests\Models\CMS\CmsUser u', - 'SELECT c0.username AS c0__username, c0.name AS c0__name FROM cms_users c0' + 'SELECT c0_.username AS username0, c0_.name AS name1 FROM cms_users c0_' ); } @@ -51,7 +51,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.phonenumbers p', - 'SELECT c0.id AS c0__id, c0.status AS c0__status, c0.username AS c0__username, c0.name AS c0__name, c1.phonenumber AS c1__phonenumber FROM cms_users c0 INNER JOIN cms_phonenumbers c1 ON c0.id = c1.user_id' + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c1_.phonenumber AS phonenumber4 FROM cms_users c0_ INNER JOIN cms_phonenumbers c1_ ON c0_.id = c1_.user_id' ); } @@ -59,7 +59,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u, a FROM Doctrine\Tests\Models\Forum\ForumUser u JOIN u.avatar a', - 'SELECT f0.id AS f0__id, f0.username AS f0__username, f1.id AS f1__id FROM forum_users f0 INNER JOIN forum_avatars f1 ON f0.avatar_id = f1.id' + 'SELECT f0_.id AS id0, f0_.username AS username1, f1_.id AS id2 FROM forum_users f0_ INNER JOIN forum_avatars f1_ ON f0_.avatar_id = f1_.id' ); } @@ -67,7 +67,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT DISTINCT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u', - 'SELECT DISTINCT c0.name AS c0__name FROM cms_users c0' + 'SELECT DISTINCT c0_.name AS name0 FROM cms_users c0_' ); } @@ -75,7 +75,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT COUNT(u.id) FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id', - 'SELECT COUNT(c0.id) AS dctrn__0 FROM cms_users c0 GROUP BY c0.id' + 'SELECT COUNT(c0_.id) AS sclr0 FROM cms_users c0_ GROUP BY c0_.id' ); } @@ -83,7 +83,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.id = ?1', - 'SELECT f0.id AS f0__id, f0.username AS f0__username FROM forum_users f0 WHERE f0.id = ?' + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.id = ?' ); } @@ -91,7 +91,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name', - 'SELECT f0.id AS f0__id, f0.username AS f0__username FROM forum_users f0 WHERE f0.username = :name' + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.username = :name' ); } @@ -99,7 +99,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name and u.username = :name2', - 'SELECT f0.id AS f0__id, f0.username AS f0__username FROM forum_users f0 WHERE f0.username = :name AND f0.username = :name2' + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.username = :name AND f0_.username = :name2' ); } @@ -107,7 +107,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'select u from Doctrine\Tests\Models\Forum\ForumUser u where (u.username = :name OR u.username = :name2) AND u.id = :id', - 'SELECT f0.id AS f0__id, f0.username AS f0__username FROM forum_users f0 WHERE (f0.username = :name OR f0.username = :name2) AND f0.id = :id' + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE (f0_.username = :name OR f0_.username = :name2) AND f0_.id = :id' ); } @@ -115,7 +115,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT COUNT(DISTINCT u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u', - 'SELECT COUNT(DISTINCT c0.name) AS dctrn__0 FROM cms_users c0' + 'SELECT COUNT(DISTINCT c0_.name) AS sclr0 FROM cms_users c0_' ); } @@ -124,7 +124,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE '%foo OR bar%'", - "SELECT c0.name AS c0__name FROM cms_users c0 WHERE c0.name LIKE '%foo OR bar%'" + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE c0_.name LIKE '%foo OR bar%'" ); } @@ -132,7 +132,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000', - 'SELECT c0.id AS c0__id, c0.status AS c0__status, c0.username AS c0__username, c0.name AS c0__name FROM cms_users c0 WHERE ((c0.id + 5000) * c0.id + 3) < 10000000' + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE ((c0_.id + 5000) * c0_.id + 3) < 10000000' ); } @@ -140,11 +140,11 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u.id, a.id from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a', - 'SELECT c0.id AS c0__id, c1.id AS c1__id FROM cms_users c0 LEFT JOIN cms_articles c1 ON c0.id = c1.user_id' + 'SELECT c0_.id AS id0, c1_.id AS id1 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id' ); $this->assertSqlGeneration( 'SELECT u.id, a.id from Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles a', - 'SELECT c0.id AS c0__id, c1.id AS c1__id FROM cms_users c0 INNER JOIN cms_articles c1 ON c0.id = c1.user_id' + 'SELECT c0_.id AS id0, c1_.id AS id1 FROM cms_users c0_ INNER JOIN cms_articles c1_ ON c0_.id = c1_.user_id' ); } @@ -152,7 +152,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u.id, a.id, p, c.id from Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles a JOIN u.phonenumbers p JOIN a.comments c', - 'SELECT c0.id AS c0__id, c1.id AS c1__id, c2.phonenumber AS c2__phonenumber, c3.id AS c3__id FROM cms_users c0 INNER JOIN cms_articles c1 ON c0.id = c1.user_id INNER JOIN cms_phonenumbers c2 ON c0.id = c2.user_id INNER JOIN cms_comments c3 ON c1.id = c3.article_id' + 'SELECT c0_.id AS id0, c1_.id AS id1, c2_.phonenumber AS phonenumber2, c3_.id AS id3 FROM cms_users c0_ INNER JOIN cms_articles c1_ ON c0_.id = c1_.user_id INNER JOIN cms_phonenumbers c2_ ON c0_.id = c2_.user_id INNER JOIN cms_comments c3_ ON c1_.id = c3_.article_id' ); } @@ -160,7 +160,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(TRAILING ' ' FROM u.name) = 'someone'", - "SELECT c0.name AS c0__name FROM cms_users c0 WHERE TRIM(TRAILING ' ' FROM c0.name) = 'someone'" + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE TRIM(TRAILING ' ' FROM c0_.name) = 'someone'" ); } @@ -169,7 +169,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id BETWEEN ?1 AND ?2", - "SELECT c0.name AS c0__name FROM cms_users c0 WHERE c0.id BETWEEN ? AND ?" + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE c0_.id BETWEEN ? AND ?" ); } @@ -179,7 +179,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(u.name) = 'someone'", // String quoting in the SQL usually depends on the database platform. // This test works with a mock connection which uses ' for string quoting. - "SELECT c0.name AS c0__name FROM cms_users c0 WHERE TRIM(FROM c0.name) = 'someone'" + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE TRIM(FROM c0_.name) = 'someone'" ); } @@ -188,7 +188,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN(46)", - "SELECT c0.name AS c0__name FROM cms_users c0 WHERE c0.id IN (46)" + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE c0_.id IN (46)" ); } @@ -196,7 +196,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN (1, 2)', - 'SELECT c0.id AS c0__id, c0.status AS c0__status, c0.username AS c0__username, c0.name AS c0__name FROM cms_users c0 WHERE c0.id IN (1, 2)' + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id IN (1, 2)' ); } @@ -204,7 +204,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (1)', - 'SELECT c0.id AS c0__id, c0.status AS c0__status, c0.username AS c0__username, c0.name AS c0__name FROM cms_users c0 WHERE c0.id NOT IN (1)' + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id NOT IN (1)' ); } @@ -216,21 +216,21 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase $connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\MySqlPlatform); $this->assertSqlGeneration( "SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, 's') = ?1", - "SELECT c0.id AS c0__id FROM cms_users c0 WHERE CONCAT(c0.name, 's') = ?" + "SELECT c0_.id AS id0 FROM cms_users c0_ WHERE CONCAT(c0_.name, 's') = ?" ); $this->assertSqlGeneration( "SELECT CONCAT(u.id, u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1", - "SELECT CONCAT(c0.id, c0.name) AS dctrn__0 FROM cms_users c0 WHERE c0.id = ?" + "SELECT CONCAT(c0_.id, c0_.name) AS sclr0 FROM cms_users c0_ WHERE c0_.id = ?" ); $connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform); $this->assertSqlGeneration( "SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, 's') = ?1", - "SELECT c0.id AS c0__id FROM cms_users c0 WHERE c0.name || 's' = ?" + "SELECT c0_.id AS id0 FROM cms_users c0_ WHERE c0_.name || 's' = ?" ); $this->assertSqlGeneration( "SELECT CONCAT(u.id, u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1", - "SELECT c0.id || c0.name AS dctrn__0 FROM cms_users c0 WHERE c0.id = ?" + "SELECT c0_.id || c0_.name AS sclr0 FROM cms_users c0_ WHERE c0_.id = ?" ); $connMock->setDatabasePlatform($orgPlatform); diff --git a/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php index 30dca2161..6646891f9 100644 --- a/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php @@ -60,11 +60,11 @@ class UpdateSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1', - 'UPDATE cms_users c0 SET c0.name = ?' + 'UPDATE cms_users c0_ SET c0_.name = ?' ); $this->assertSqlGeneration( 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1, u.username = ?2', - 'UPDATE cms_users c0 SET c0.name = ?, c0.username = ?' + 'UPDATE cms_users c0_ SET c0_.name = ?, c0_.username = ?' ); } diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index 348f2cdac..26acd2c59 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -30,7 +30,8 @@ class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\CMS\CmsUser', 'Doctrine\Tests\Models\CMS\CmsPhonenumber', 'Doctrine\Tests\Models\CMS\CmsAddress', - 'Doctrine\Tests\Models\CMS\CmsGroup' + 'Doctrine\Tests\Models\CMS\CmsGroup', + 'Doctrine\Tests\Models\CMS\CmsArticle' ), 'forum' => array(), 'company' => array(), @@ -53,6 +54,7 @@ class OrmFunctionalTestCase extends OrmTestCase $conn->exec('DELETE FROM cms_groups'); $conn->exec('DELETE FROM cms_addresses'); $conn->exec('DELETE FROM cms_phonenumbers'); + $conn->exec('DELETE FROM cms_articles'); $conn->exec('DELETE FROM cms_users'); } $this->_em->clear();