Commit 523c93c2 authored by romanb's avatar romanb

[2.0] Refactored SQL query building process and hydration. Hydration should...

[2.0] Refactored SQL query building process and hydration. Hydration should now support result sets with any number of root components. Introducing ResultSetMapping that is used by hydration instead of queryComponents. This allows mapping of arbitrary SQL queries (NativeQuery).
parent 62204af8
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
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);
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Common;
/**
* Contract for classes that are potential listeners of a <tt>NotifyPropertyChanged</tt>
* implementor.
*
* @author robo
* @since 2.0
*/
interface PropertyChangedListener
{
public function propertyChanged($sender, $propertyName, $oldValue, $newValue);
}
......@@ -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
......@@ -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;
}
// Check the type of the relation (many or single-valued)
if ( ! $map['relation']->isOneToOne()) {
$oneToOne = false;
if (isset($nonemptyComponents[$dqlAlias])) {
if ( ! isset($baseElement[$relationAlias])) {
if ($this->_resultSetMapping->hasParentAlias($dqlAlias)) {
$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();
}
} else {
$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = null;
} else if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = $data;
}
}
$coll =& $baseElement[$relationAlias];
$coll =& $baseElement[$relationAlias];
if ($coll !== null) {
$this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne);
}
if ($coll !== null) {
$this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne);
} else {
$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]];
}
$this->updateResultPointer($result, $index, $dqlAlias, false);
//unset($rowData[$rootAlias]);
}
}
......
......@@ -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;
// 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;
}
$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() && 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);
// 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);
$oid = spl_object_hash($baseElement);
// 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 {
$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));
}
} 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);
$coll = $this->_metadataMap[$oid]
->getReflectionProperty($relationAlias)
->getValue($baseElement);
if ($coll !== null) {
$this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne);
if ($coll !== null) {
$this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne);
}
} else {
// 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]];
}
$this->updateResultPointer($result, $index, $dqlAlias, false);
//unset($rowData[$dqlAlias]);
}
}
......
......@@ -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 <tt>NotifyPropertyChanged</tt> 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.
*
......
......@@ -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));
}
}
......
......@@ -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();
......
......@@ -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
......@@ -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
......@@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
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
......@@ -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.
......
......@@ -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 <type> $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*.
......
......@@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query;
......
......@@ -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'];
......
......@@ -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
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query;
/**
* A ResultSetMapping describes how a result set of an SQL query maps to a Doctrine result.
*
* @author Roman Borschel <roman@code-factory.org>
* @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 <type> $class
* @param <type> $alias The alias for this class. The alias must be unique within this ResultSetMapping.
* @param <type> $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 <type> $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 <type> $columnName
* @return <type>
*/
public function getEntityAlias($columnName)
{
return $this->_columnOwnerMap[$columnName];
}
/**
*
* @param <type> $alias
* @return <type>
*/
public function getParentAlias($alias)
{
return $this->_parentAliasMap[$alias];
}
public function hasParentAlias($alias)
{
return isset($this->_parentAliasMap[$alias]);
}
/**
*
* @param <type> $className
* @param <type> $columnName
* @return <type>
*/
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);
}
}
......@@ -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)
{
if ( ! isset($this->_dqlToSqlAliasMap[$tableName])) {
$this->_dqlToSqlAliasMap[$tableName] = strtolower(substr($tableName, 0, 1)) . $this->_tableAliasCounter++ . '_';
}
return $this->_dqlToSqlAliasMap[$tableName];
}
public function getSqlColumnAlias($columnName)
{
return strtolower(substr($tableName, 0, 1)) . $this->_tableAliasCounter++;
return $columnName . $this->_aliasCounter++;
}
}
\ No newline at end of file
......@@ -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
......
......@@ -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 <roman@code-factory.org>
*/
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
......@@ -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];
......
......@@ -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"));
......
......@@ -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);
}
}
......@@ -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;
}
......
......@@ -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) {
......
......@@ -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;
}
......
......@@ -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
<?php
namespace Doctrine\Tests\ORM\Hydration;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
require_once __DIR__ . '/../../TestInit.php';
/**
* Description of ResultSetMappingTest
*
* @author robo
*/
class ResultSetMappingTest extends \Doctrine\Tests\OrmTestCase
{
private $_rsm;
private $_em;
protected function setUp() {
parent::setUp();
$this->_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'));
}
}
......@@ -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));
......
......@@ -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) {}
}
......
......@@ -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;
}
......
......@@ -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
......@@ -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');
......
......@@ -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 (?, ?)'
);
}
......
......@@ -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);
......
......@@ -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 = ?'
);
}
......
......@@ -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();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment