Merge branch 'hotfix/resolve-target-entity-also-in-discriminator-map'
Close #1257
This commit is contained in:
commit
dfa4bbd67a
@ -70,6 +70,18 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
*/
|
||||
private $embeddablesActiveNesting = array();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function loadMetadata($name)
|
||||
{
|
||||
$loaded = parent::loadMetadata($name);
|
||||
|
||||
array_map([$this, 'resolveDiscriminatorValue'], array_map([$this, 'getMetadataFor'], $loaded));
|
||||
|
||||
return $loaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
@ -270,9 +282,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
if ( ! $class->discriminatorColumn) {
|
||||
throw MappingException::missingDiscriminatorColumn($class->name);
|
||||
}
|
||||
} else if ($parent && !$class->reflClass->isAbstract() && !in_array($class->name, array_values($class->discriminatorMap))) {
|
||||
// enforce discriminator map for all entities of an inheritance hierarchy, otherwise problems will occur.
|
||||
throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name, $class->rootEntityName);
|
||||
}
|
||||
} else if ($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
|
||||
@ -288,6 +297,47 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
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.
|
||||
*
|
||||
* @param ClassMetadata $metadata
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws MappingException
|
||||
*/
|
||||
private function resolveDiscriminatorValue(ClassMetadata $metadata)
|
||||
{
|
||||
if ($metadata->discriminatorValue
|
||||
|| ! $metadata->discriminatorMap
|
||||
|| $metadata->isMappedSuperclass
|
||||
|| $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
|
||||
*
|
||||
|
@ -2745,15 +2745,18 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$className = ltrim($className, '\\');
|
||||
$this->discriminatorMap[$name] = $className;
|
||||
|
||||
if ($this->name == $className) {
|
||||
if ($this->name === $className) {
|
||||
$this->discriminatorValue = $name;
|
||||
} else {
|
||||
if ( ! class_exists($className)) {
|
||||
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
|
||||
}
|
||||
if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses)) {
|
||||
$this->subClasses[] = $className;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! (class_exists($className) || interface_exists($className))) {
|
||||
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
|
||||
}
|
||||
|
||||
if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses)) {
|
||||
$this->subClasses[] = $className;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ namespace Doctrine\Tests\Models\CompositeKeyInheritance;
|
||||
* @Entity
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"child" = "JoinedChildClass",})
|
||||
* @DiscriminatorMap({"child" = "JoinedChildClass", "root" = "JoinedRootClass"})
|
||||
*/
|
||||
class JoinedRootClass
|
||||
{
|
||||
|
@ -5,7 +5,7 @@ namespace Doctrine\Tests\Models\CompositeKeyInheritance;
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"child" = "SingleChildClass",})
|
||||
* @DiscriminatorMap({"child" = "SingleChildClass", "root" = "SingleRootClass"})
|
||||
*/
|
||||
class SingleRootClass
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ class DDC1113Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorMap({"car" = "DDC1113Car", "bus" = "DDC1113Bus"})
|
||||
* @DiscriminatorMap({"vehicle" = "DDC1113Vehicle", "car" = "DDC1113Car", "bus" = "DDC1113Bus"})
|
||||
*/
|
||||
class DDC1113Vehicle
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ class DDC1454Picture extends DDC1454File
|
||||
* @Entity
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"picture" = "DDC1454Picture"})
|
||||
* @DiscriminatorMap({"file" = "DDC1454File", "picture" = "DDC1454Picture"})
|
||||
*/
|
||||
class DDC1454File
|
||||
{
|
||||
|
@ -115,7 +115,7 @@ class DDC1509Picture
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"file" = "DDC1509File"})
|
||||
* @DiscriminatorMap({"abstractFile" = "DDC1509AbstractFile", "file" = "DDC1509File"})
|
||||
*/
|
||||
class DDC1509AbstractFile
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ class DDC1787Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
* @Entity
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"bar" = "DDC1787Bar"})
|
||||
* @DiscriminatorMap({"bar" = "DDC1787Bar", "foo" = "DDC1787Foo"})
|
||||
*/
|
||||
class DDC1787Foo
|
||||
{
|
||||
|
@ -71,7 +71,8 @@ class DDC2012Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="type_id", type="smallint")
|
||||
* @DiscriminatorMap({
|
||||
* 1 = "DDC2012ItemPerson"
|
||||
* 1 = "DDC2012ItemPerson",
|
||||
* 2 = "DDC2012Item"
|
||||
* })
|
||||
*/
|
||||
class DDC2012Item
|
||||
|
@ -88,7 +88,7 @@ class DDC2346Foo
|
||||
* @Entity
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"baz" = "DDC2346Baz"})
|
||||
* @DiscriminatorMap({"bar" = "DDC2346Bar", "baz" = "DDC2346Baz"})
|
||||
*/
|
||||
class DDC2346Bar
|
||||
{
|
||||
|
@ -53,7 +53,8 @@ class Journalist extends Participant
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({
|
||||
* "journalist" = "Journalist",
|
||||
* "journalist" = "Journalist",
|
||||
* "participant" = "Participant",
|
||||
* })
|
||||
*/
|
||||
class Participant
|
||||
@ -71,6 +72,7 @@ class Participant
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({
|
||||
* "profile" = "ProfileStatus",
|
||||
* "status" = "Status",
|
||||
* })
|
||||
*/
|
||||
class Status
|
||||
|
85
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3300Test.php
Normal file
85
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3300Test.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\Tools\ResolveTargetEntityListener;
|
||||
|
||||
/**
|
||||
* @group DDC-3300
|
||||
*/
|
||||
class DDC3300Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function testResolveTargetEntitiesChangesDiscriminatorMapValues()
|
||||
{
|
||||
$resolveTargetEntity = new ResolveTargetEntityListener();
|
||||
|
||||
$resolveTargetEntity->addResolveTargetEntity(
|
||||
DDC3300BossInterface::INTERFACENAME,
|
||||
DDC3300Boss::CLASSNAME,
|
||||
array()
|
||||
);
|
||||
|
||||
$resolveTargetEntity->addResolveTargetEntity(
|
||||
DDC3300EmployeeInterface::INTERFACENAME,
|
||||
DDC3300Employee::CLASSNAME,
|
||||
array()
|
||||
);
|
||||
|
||||
$this->_em->getEventManager()->addEventSubscriber($resolveTargetEntity);
|
||||
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(DDC3300Person::CLASSNAME),
|
||||
));
|
||||
|
||||
$boss = new DDC3300Boss();
|
||||
$employee = new DDC3300Employee();
|
||||
|
||||
$this->_em->persist($boss);
|
||||
$this->_em->persist($employee);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$this->assertEquals($boss, $this->_em->find(DDC3300BossInterface::INTERFACENAME, $boss->id));
|
||||
$this->assertEquals($employee, $this->_em->find(DDC3300EmployeeInterface::INTERFACENAME, $employee->id));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DdiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({
|
||||
* "boss" = "Doctrine\Tests\ORM\Functional\Ticket\DDC3300BossInterface",
|
||||
* "employee" = "Doctrine\Tests\ORM\Functional\Ticket\DDC3300EmployeeInterface"
|
||||
* })
|
||||
*/
|
||||
abstract class DDC3300Person
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
/** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
|
||||
public $id;
|
||||
}
|
||||
|
||||
interface DDC3300BossInterface
|
||||
{
|
||||
const INTERFACENAME = __CLASS__;
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class DDC3300Boss extends DDC3300Person implements DDC3300BossInterface
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
}
|
||||
|
||||
interface DDC3300EmployeeInterface
|
||||
{
|
||||
const INTERFACENAME = __CLASS__;
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class DDC3300Employee extends DDC3300Person implements DDC3300EmployeeInterface
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user