From a141aaf6632beb94981301365f7265ade8467733 Mon Sep 17 00:00:00 2001 From: Francis Besset Date: Sun, 1 May 2011 00:17:40 +0200 Subject: [PATCH] [PR-39] Throw exception when hydrating joined entity without existing parent alias (NativeQuery problem only) --- .../ORM/Internal/Hydration/ObjectHydrator.php | 28 +++++++++++-------- .../Tests/ORM/Functional/NativeQueryTest.php | 19 +++++++++++++ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php index a820832f5..381fd4ab1 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php @@ -39,9 +39,9 @@ class ObjectHydrator extends AbstractHydrator * This local cache is maintained between hydration runs and not cleared. */ private $_ce = array(); - + /* The following parts are reinitialized on every hydration run. */ - + private $_identifierMap; private $_resultPointers; private $_idTemplate; @@ -50,7 +50,7 @@ class ObjectHydrator extends AbstractHydrator private $_initializedCollections = array(); private $_existingCollections = array(); //private $_createdEntities; - + /** @override */ protected function _prepare() @@ -71,10 +71,14 @@ class ObjectHydrator extends AbstractHydrator if ( ! isset($this->_ce[$className])) { $this->_ce[$className] = $class; } - + // Remember which associations are "fetch joined", so that we know where to inject // collection stubs or proxies and where not. if (isset($this->_rsm->relationMap[$dqlAlias])) { + if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) { + throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]); + } + $sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]]; $sourceClass = $this->_getClassMetadata($sourceClassName); $assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]]; @@ -185,7 +189,7 @@ class ObjectHydrator extends AbstractHydrator return $value; } - + /** * Gets an entity instance. * @@ -195,7 +199,7 @@ class ObjectHydrator extends AbstractHydrator */ private function _getEntity(array $data, $dqlAlias) { - $className = $this->_rsm->aliasMap[$dqlAlias]; + $className = $this->_rsm->aliasMap[$dqlAlias]; if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) { $discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]]; $className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]]; @@ -203,7 +207,7 @@ class ObjectHydrator extends AbstractHydrator } return $this->_uow->createEntity($className, $data, $this->_hints); } - + private function _getEntityFromIdentityMap($className, array $data) { $class = $this->_ce[$className]; @@ -217,7 +221,7 @@ class ObjectHydrator extends AbstractHydrator return $this->_uow->tryGetByIdHash($data[$class->identifier[0]], $class->rootEntityName); } } - + /** * Gets a ClassMetadata instance from the local cache. * If the instance is not yet in the local cache, it is loaded into the @@ -275,7 +279,7 @@ class ObjectHydrator extends AbstractHydrator // Hydrate the data chunks foreach ($rowData as $dqlAlias => $data) { $entityName = $this->_rsm->aliasMap[$dqlAlias]; - + if (isset($this->_rsm->parentAliasMap[$dqlAlias])) { // It's a joined result @@ -286,7 +290,7 @@ class ObjectHydrator extends AbstractHydrator // Get a reference to the parent object to which the joined element belongs. if ($this->_rsm->isMixed && isset($this->_rootAliases[$parentAlias])) { - $first = reset($this->_resultPointers); + $first = reset($this->_resultPointers); $parentObject = $this->_resultPointers[$parentAlias][key($first)]; } else if (isset($this->_resultPointers[$parentAlias])) { $parentObject = $this->_resultPointers[$parentAlias]; @@ -311,11 +315,11 @@ class ObjectHydrator extends AbstractHydrator } else if ( ! isset($this->_existingCollections[$collKey])) { $reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField); } - + $indexExists = isset($this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]); $index = $indexExists ? $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false; $indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false; - + if ( ! $indexExists || ! $indexIsValid) { if (isset($this->_existingCollections[$collKey])) { // Collection exists, only look for the element in the identity map. diff --git a/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php b/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php index 2a09b8310..f997c6c01 100644 --- a/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php @@ -246,5 +246,24 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase $rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addJoinedEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', 'a', 'u', 'address'); } + + /** + * @group PR-39 + */ + public function testUnknownParentAliasThrowsException() + { + $rsm = new ResultSetMappingBuilder($this->_em); + $rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', 'a', 'un', 'address', array('id' => 'a_id')); + + $query = $this->_em->createNativeQuery('SELECT u.*, a.*, a.id AS a_id FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm); + $query->setParameter(1, 'romanb'); + + $this->setExpectedException( + "Doctrine\ORM\Internal\Hydration\HydrationException", + "The parent object of entity result with alias 'a' was not found. The parent alias is 'un'." + ); + $users = $query->getResult(); + } }