From c7b4c9bf0fbc5dca830e0a797cea470510def994 Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Tue, 30 Jul 2013 01:29:34 -0400 Subject: [PATCH] Fixed DDC-1884. --- .../ORM/Internal/Hydration/ArrayHydrator.php | 26 +-- tests/Doctrine/Tests/Models/Taxi/Car.php | 42 +++++ tests/Doctrine/Tests/Models/Taxi/Driver.php | 37 ++++ tests/Doctrine/Tests/Models/Taxi/PaidRide.php | 42 +++++ tests/Doctrine/Tests/Models/Taxi/Ride.php | 32 ++++ .../ORM/Functional/Ticket/DDC1884Test.php | 158 ++++++++++++++++++ .../Doctrine/Tests/OrmFunctionalTestCase.php | 14 +- 7 files changed, 338 insertions(+), 13 deletions(-) create mode 100644 tests/Doctrine/Tests/Models/Taxi/Car.php create mode 100644 tests/Doctrine/Tests/Models/Taxi/Driver.php create mode 100644 tests/Doctrine/Tests/Models/Taxi/PaidRide.php create mode 100644 tests/Doctrine/Tests/Models/Taxi/Ride.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1884Test.php diff --git a/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php index bb18f32c6..98cb937d2 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php @@ -185,7 +185,7 @@ class ArrayHydrator extends AbstractHydrator if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) { $baseElement[$relationAlias] = null; - } else if ( ! isset($baseElement[$relationAlias])) { + } else if ( ! isset($baseElement[$relationAlias]) || ! isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]])) { $baseElement[$relationAlias] = $data; } } @@ -204,19 +204,20 @@ class ArrayHydrator extends AbstractHydrator // if this row has a NULL value for the root result id then make it a null result. if ( ! isset($nonemptyComponents[$dqlAlias]) ) { - if ($this->_rsm->isMixed) { - $result[] = array($entityKey => null); - } else { - $result[] = null; - } + $result[] = ($this->_rsm->isMixed) + ? array($entityKey => null) + : null; + $resultKey = $this->_resultCounter; ++$this->_resultCounter; + continue; } // Check for an existing element if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { $element = $rowData[$dqlAlias]; + if ($this->_rsm->isMixed) { $element = array($entityKey => $element); } @@ -239,6 +240,7 @@ class ArrayHydrator extends AbstractHydrator ++$this->_resultCounter; }*/ } + $this->updateResultPointer($result, $index, $dqlAlias, false); } } @@ -279,6 +281,12 @@ class ArrayHydrator extends AbstractHydrator return; } + if ($oneToOne) { + $this->_resultPointers[$dqlAlias] =& $coll; + + return; + } + if ($index !== false) { $this->_resultPointers[$dqlAlias] =& $coll[$index]; @@ -289,12 +297,6 @@ class ArrayHydrator extends AbstractHydrator return; } - if ($oneToOne) { - $this->_resultPointers[$dqlAlias] =& $coll; - - return; - } - end($coll); $this->_resultPointers[$dqlAlias] =& $coll[key($coll)]; diff --git a/tests/Doctrine/Tests/Models/Taxi/Car.php b/tests/Doctrine/Tests/Models/Taxi/Car.php new file mode 100644 index 000000000..2db5ecd36 --- /dev/null +++ b/tests/Doctrine/Tests/Models/Taxi/Car.php @@ -0,0 +1,42 @@ +brand = $brand; + } + + public function setModel($model) + { + $this->model = $model; + } +} diff --git a/tests/Doctrine/Tests/Models/Taxi/Driver.php b/tests/Doctrine/Tests/Models/Taxi/Driver.php new file mode 100644 index 000000000..ccb493f1d --- /dev/null +++ b/tests/Doctrine/Tests/Models/Taxi/Driver.php @@ -0,0 +1,37 @@ +name = $name; + } +} diff --git a/tests/Doctrine/Tests/Models/Taxi/PaidRide.php b/tests/Doctrine/Tests/Models/Taxi/PaidRide.php new file mode 100644 index 000000000..040e3917e --- /dev/null +++ b/tests/Doctrine/Tests/Models/Taxi/PaidRide.php @@ -0,0 +1,42 @@ +driver = $driver; + $this->car = $car; + } + + public function setFare($fare) + { + $this->fare = $fare; + } +} diff --git a/tests/Doctrine/Tests/Models/Taxi/Ride.php b/tests/Doctrine/Tests/Models/Taxi/Ride.php new file mode 100644 index 000000000..e90a38217 --- /dev/null +++ b/tests/Doctrine/Tests/Models/Taxi/Ride.php @@ -0,0 +1,32 @@ +driver = $driver; + $this->car = $car; + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1884Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1884Test.php new file mode 100644 index 000000000..de02e3067 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1884Test.php @@ -0,0 +1,158 @@ + + */ +class DDC1884Test extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() + { + $this->useModelSet('taxi'); + parent::setUp(); + + list($bimmer, $crysler, $merc, $volvo) = $this->createCars('Doctrine\Tests\Models\Taxi\Car'); + list($john, $foo) = $this->createDrivers('Doctrine\Tests\Models\Taxi\Driver'); + $this->_em->flush(); + + $ride1 = new Ride($john, $bimmer); + $ride2 = new Ride($john, $merc); + $ride3 = new Ride($john, $volvo); + $ride4 = new Ride($foo, $merc); + + $this->_em->persist($ride1); + $this->_em->persist($ride2); + $this->_em->persist($ride3); + $this->_em->persist($ride4); + + $ride5 = new PaidRide($john, $bimmer); + $ride5->setFare(10.50); + + $ride6 = new PaidRide($john, $merc); + $ride6->setFare(16.00); + + $ride7 = new PaidRide($john, $volvo); + $ride7->setFare(20.70); + + $ride8 = new PaidRide($foo, $merc); + $ride8->setFare(32.15); + + $this->_em->persist($ride5); + $this->_em->persist($ride6); + $this->_em->persist($ride7); + $this->_em->persist($ride8); + + $this->_em->flush(); + } + + private function createCars($class) + { + $bimmer = new $class; + $bimmer->setBrand('BMW'); + $bimmer->setModel('7-Series'); + + $crysler = new $class; + $crysler->setBrand('Crysler'); + $crysler->setModel('300'); + + $merc = new $class; + $merc->setBrand('Mercedes'); + $merc->setModel('C-Class'); + + $volvo = new $class; + $volvo->setBrand('Volvo'); + $volvo->setModel('XC90'); + + $this->_em->persist($bimmer); + $this->_em->persist($crysler); + $this->_em->persist($merc); + $this->_em->persist($volvo); + + return array($bimmer, $crysler, $merc, $volvo); + } + + private function createDrivers($class) + { + $john = new $class; + $john->setName('John Doe'); + + $foo = new $class; + $foo->setName('Foo Bar'); + + $this->_em->persist($foo); + $this->_em->persist($john); + + return array($john, $foo); + } + + /** + * 1) Ride contains only columns that are part of its composite primary key + * 2) We use fetch joins here + */ + public function testSelectFromInverseSideWithCompositePkAndSolelyIdentifierColumnsUsingFetchJoins() + { + $qb = $this->_em->createQueryBuilder(); + + $result = $qb->select('d, dr, c') + ->from('Doctrine\Tests\Models\Taxi\Driver', 'd') + ->leftJoin('d.freeDriverRides', 'dr') + ->leftJoin('dr.car', 'c') + ->where('d.name = ?1') + ->setParameter(1, 'John Doe') + ->getQuery() + ->getArrayResult(); + + $this->assertCount(1, $result); + $this->assertArrayHasKey('freeDriverRides', $result[0]); + $this->assertCount(3, $result[0]['freeDriverRides']); + } + + /** + * 1) PaidRide contains an extra column that is not part of the composite primary key + * 2) Again we will use fetch joins + */ + public function testSelectFromInverseSideWithCompositePkUsingFetchJoins() + { + $qb = $this->_em->createQueryBuilder(); + + $result = $qb->select('d, dr, c') + ->from('Doctrine\Tests\Models\Taxi\Driver', 'd') + ->leftJoin('d.driverRides', 'dr') + ->leftJoin('dr.car', 'c') + ->where('d.name = ?1') + ->setParameter(1, 'John Doe') + ->getQuery()->getArrayResult(); + + $this->assertCount(1, $result); + $this->assertArrayHasKey('driverRides', $result[0]); + $this->assertCount(3, $result[0]['driverRides']); + } + + /** + * The other way around will fail too + */ + public function testSelectFromOwningSideUsingFetchJoins() + { + $qb = $this->_em->createQueryBuilder(); + + $result = $qb->select('r, d, c') + ->from('Doctrine\Tests\Models\Taxi\PaidRide', 'r') + ->leftJoin('r.driver', 'd') + ->leftJoin('r.car', 'c') + ->where('d.name = ?1') + ->setParameter(1, 'John Doe') + ->getQuery()->getArrayResult(); + + $this->assertCount(3, $result); + $this->assertArrayHasKey('driver', $result[0]); + $this->assertArrayHasKey('car', $result[0]); + } +} diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index 9c922802c..1b70be721 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -155,7 +155,13 @@ abstract class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\CompositeKeyInheritance\JoinedChildClass', 'Doctrine\Tests\Models\CompositeKeyInheritance\SingleRootClass', 'Doctrine\Tests\Models\CompositeKeyInheritance\SingleChildClass', - ) + ), + 'taxi' => array( + 'Doctrine\Tests\Models\Taxi\PaidRide', + 'Doctrine\Tests\Models\Taxi\Ride', + 'Doctrine\Tests\Models\Taxi\Car', + 'Doctrine\Tests\Models\Taxi\Driver', + ), ); /** @@ -284,6 +290,12 @@ abstract class OrmFunctionalTestCase extends OrmTestCase $conn->executeUpdate('DELETE FROM SingleRootClass'); } + if (isset($this->_usedModelSets['taxi'])) { + $conn->executeUpdate('DELETE FROM taxi_paid_ride'); + $conn->executeUpdate('DELETE FROM taxi_ride'); + $conn->executeUpdate('DELETE FROM taxi_car'); + $conn->executeUpdate('DELETE FROM taxi_driver'); + } $this->_em->clear(); }