diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index b38a212c9..5fe4fa1e5 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -24,6 +24,8 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Events; use Doctrine\ORM\Mapping\ClassMetadata; use PDO; +use function array_map; +use function in_array; /** * Base class for all hydrators. A hydrator is a class that provides some form @@ -296,11 +298,8 @@ abstract class AbstractHydrator // If there are field name collisions in the child class, then we need // to only hydrate if we are looking at the correct discriminator value - if( - isset($cacheKeyInfo['discriminatorColumn']) && - isset($data[$cacheKeyInfo['discriminatorColumn']]) && - // Note: loose comparison required. See https://github.com/doctrine/doctrine2/pull/6304#issuecomment-323294442 - $data[$cacheKeyInfo['discriminatorColumn']] != $cacheKeyInfo['discriminatorValue'] + if (isset($cacheKeyInfo['discriminatorColumn'], $data[$cacheKeyInfo['discriminatorColumn']]) + && ! in_array((string) $data[$cacheKeyInfo['discriminatorColumn']], $cacheKeyInfo['discriminatorValues'], true) ) { break; } @@ -401,7 +400,8 @@ abstract class AbstractHydrator $columnInfo, [ 'discriminatorColumn' => $this->_rsm->discriminatorColumns[$ownerMap], - 'discriminatorValue' => $classMetadata->discriminatorValue + 'discriminatorValue' => $classMetadata->discriminatorValue, + 'discriminatorValues' => $this->getDiscriminatorValues($classMetadata), ] ); } @@ -454,6 +454,23 @@ abstract class AbstractHydrator return null; } + /** + * @return string[] + */ + private function getDiscriminatorValues(ClassMetadata $classMetadata) : array + { + $values = array_map( + function (string $subClass) : string { + return (string) $this->getClassMetadata($subClass)->discriminatorValue; + }, + $classMetadata->subClasses + ); + + $values[] = (string) $classMetadata->discriminatorValue; + + return $values; + } + /** * Retrieve ClassMetadata associated to entity class name. * diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH6937Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH6937Test.php new file mode 100644 index 000000000..756111b98 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH6937Test.php @@ -0,0 +1,119 @@ +setUpEntitySchema([GH6937Person::class, GH6937Employee::class, GH6937Manager::class]); + } + + public function testPhoneNumberIsPopulatedWithFind() : void + { + $manager = new GH6937Manager(); + $manager->name = 'Kevin'; + $manager->phoneNumber = '555-5555'; + $manager->department = 'Accounting'; + + $this->_em->persist($manager); + $this->_em->flush(); + $this->_em->clear(); + + $persistedManager = $this->_em->find(GH6937Person::class, $manager->id); + + self::assertSame('Kevin', $persistedManager->name); + self::assertSame('555-5555', $persistedManager->phoneNumber); + self::assertSame('Accounting', $persistedManager->department); + } + + public function testPhoneNumberIsPopulatedWithQueryBuilderUsingSimpleObjectHydrator() : void + { + $manager = new GH6937Manager(); + $manager->name = 'Kevin'; + $manager->phoneNumber = '555-5555'; + $manager->department = 'Accounting'; + + $this->_em->persist($manager); + $this->_em->flush(); + $this->_em->clear(); + + $persistedManager = $this->_em->getRepository(GH6937Person::class) + ->createQueryBuilder('e') + ->where('e.id = :id') + ->setParameter('id', $manager->id) + ->getQuery() + ->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT); + + self::assertSame('Kevin', $persistedManager->name); + self::assertSame('555-5555', $persistedManager->phoneNumber); + self::assertSame('Accounting', $persistedManager->department); + } + + public function testPhoneNumberIsPopulatedWithQueryBuilder() : void + { + $manager = new GH6937Manager(); + $manager->name = 'Kevin'; + $manager->phoneNumber = '555-5555'; + $manager->department = 'Accounting'; + + $this->_em->persist($manager); + $this->_em->flush(); + $this->_em->clear(); + + $persistedManager = $this->_em->getRepository(GH6937Person::class) + ->createQueryBuilder('e') + ->where('e.id = :id') + ->setParameter('id', $manager->id) + ->getQuery() + ->getOneOrNullResult(); + + self::assertSame('Kevin', $persistedManager->name); + self::assertSame('555-5555', $persistedManager->phoneNumber); + self::assertSame('Accounting', $persistedManager->department); + } +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"employee"=GH6937Employee::class, "manager"=GH6937Manager::class}) + */ +abstract class GH6937Person +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + + /** @Column(type="string") */ + public $name; +} + +/** + * @Entity + */ +abstract class GH6937Employee extends GH6937Person +{ + /** @Column(type="string") */ + public $phoneNumber; +} + +/** + * @Entity + */ +class GH6937Manager extends GH6937Employee +{ + /** @Column(type="string") */ + public $department; +}