1
0
mirror of synced 2025-02-20 22:23:14 +03:00

Merge branch 'hotfix/resolve-target-entity-also-in-discriminator-map'

Close #1257
This commit is contained in:
Marco Pivetta 2015-01-22 09:52:17 +01:00
commit dfa4bbd67a
12 changed files with 161 additions and 20 deletions

View File

@ -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
*

View File

@ -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;
}
}

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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

View File

@ -88,7 +88,7 @@ class DDC2346Foo
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"baz" = "DDC2346Baz"})
* @DiscriminatorMap({"bar" = "DDC2346Bar", "baz" = "DDC2346Baz"})
*/
class DDC2346Bar
{

View File

@ -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

View 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__;
}