Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolving target entity in discriminator map omits fields from subtables #8402

Merged
58 changes: 6 additions & 52 deletions lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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
Expand All @@ -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
*
Expand Down
6 changes: 6 additions & 0 deletions lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']);
}
}
}

/**
Expand Down
26 changes: 23 additions & 3 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3300Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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"
Expand All @@ -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
Expand All @@ -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;
}
}