diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index 36251411147..0c1936757f6 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -41,12 +41,12 @@ use ReflectionClass; use ReflectionException; -use function array_map; use function assert; use function class_exists; use function count; use function end; use function explode; +use function in_array; use function is_subclass_of; use function strpos; use function strtolower; @@ -77,18 +77,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory /** @var mixed[] */ private $embeddablesActiveNesting = []; - /** - * {@inheritDoc} - */ - protected function loadMetadata($name) - { - $loaded = parent::loadMetadata($name); - - array_map([$this, 'resolveDiscriminatorValue'], array_map([$this, 'getMetadataFor'], $loaded)); - - return $loaded; - } - /** * @return void */ @@ -295,6 +283,11 @@ protected function validateRuntimeMetadata($class, $parent) throw MappingException::invalidClassInDiscriminatorMap($subClass, $class->name); } } + } else { + assert($parent instanceof ClassMetadataInfo); // https://github.com/doctrine/orm/issues/8746 + if ((! $class->reflClass || ! $class->reflClass->isAbstract()) && ! in_array($class->name, $parent->discriminatorMap)) { + throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name, $class->rootEntityName); + } } } elseif ($class->isMappedSuperclass && $class->name === $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) { // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy @@ -310,45 +303,6 @@ protected function newClassMetadataInstance($className) return new ClassMetadata($className, $this->em->getConfiguration()->getNamingStrategy()); } - /** - * Populates the discriminator value of the given metadata (if not set) by iterating over discriminator - * map classes and looking for a fitting one. - * - * @throws MappingException - */ - private function resolveDiscriminatorValue(ClassMetadata $metadata): void - { - if ( - $metadata->discriminatorValue - || ! $metadata->discriminatorMap - || $metadata->isMappedSuperclass - || ! $metadata->reflClass - || $metadata->reflClass->isAbstract() - ) { - return; - } - - // minor optimization: avoid loading related metadata when not needed - foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) { - if ($discriminatorClass === $metadata->name) { - $metadata->discriminatorValue = $discriminatorValue; - - return; - } - } - - // iterate over discriminator mappings and resolve actual referenced classes according to existing metadata - foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) { - if ($metadata->name === $this->getMetadataFor($discriminatorClass)->getName()) { - $metadata->discriminatorValue = $discriminatorValue; - - return; - } - } - - throw MappingException::mappedClassNotPartOfDiscriminatorMap($metadata->name, $metadata->rootEntityName); - } - /** * Adds a default discriminator map if no one is given * diff --git a/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php b/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php index 63b75fc1f07..9f13b63cfb9 100644 --- a/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php +++ b/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php @@ -105,6 +105,12 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $args) $args->getEntityManager()->getMetadataFactory()->setMetadataFor($interface, $cm); } } + + foreach ($cm->discriminatorMap as $value => $class) { + if (isset($this->resolveTargetEntities[$class])) { + $cm->addDiscriminatorMapClass($value, $this->resolveTargetEntities[$class]['targetEntity']); + } + } } /** diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3300Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3300Test.php index 40c96583e6f..cafb0de7257 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3300Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3300Test.php @@ -36,8 +36,8 @@ public function testResolveTargetEntitiesChangesDiscriminatorMapValues(): void ] ); - $boss = new DDC3300HumanBoss(); - $employee = new DDC3300HumanEmployee(); + $boss = new DDC3300HumanBoss('boss'); + $employee = new DDC3300HumanEmployee('employee'); $this->_em->persist($boss); $this->_em->persist($employee); @@ -53,7 +53,7 @@ public function testResolveTargetEntitiesChangesDiscriminatorMapValues(): void /** * @Entity * @InheritanceType("SINGLE_TABLE") - * @DdiscriminatorColumn(name="discr", type="string") + * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({ * "boss" = "Doctrine\Tests\ORM\Functional\Ticket\DDC3300Boss", * "employee" = "Doctrine\Tests\ORM\Functional\Ticket\DDC3300Employee" @@ -77,6 +77,16 @@ interface DDC3300Boss /** @Entity */ class DDC3300HumanBoss extends DDC3300Person implements DDC3300Boss { + /** + * @var string + * @Column(type="string") + */ + public $bossCol; + + public function __construct($bossCol) + { + $this->bossCol = $bossCol; + } } interface DDC3300Employee @@ -86,4 +96,14 @@ interface DDC3300Employee /** @Entity */ class DDC3300HumanEmployee extends DDC3300Person implements DDC3300Employee { + /** + * @var string + * @Column(type="string") + */ + public $employeeCol; + + public function __construct($employeeCol) + { + $this->employeeCol = $employeeCol; + } }