1
0
mirror of synced 2025-02-22 15:13:13 +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(); 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 * @param EntityManagerInterface $em
*/ */
@ -270,9 +282,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
if ( ! $class->discriminatorColumn) { if ( ! $class->discriminatorColumn) {
throw MappingException::missingDiscriminatorColumn($class->name); 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)) { } 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 // 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()); 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 * Adds a default discriminator map if no one is given
* *

View File

@ -2745,17 +2745,20 @@ class ClassMetadataInfo implements ClassMetadata
$className = ltrim($className, '\\'); $className = ltrim($className, '\\');
$this->discriminatorMap[$name] = $className; $this->discriminatorMap[$name] = $className;
if ($this->name == $className) { if ($this->name === $className) {
$this->discriminatorValue = $name; $this->discriminatorValue = $name;
} else {
if ( ! class_exists($className)) { return;
}
if ( ! (class_exists($className) || interface_exists($className))) {
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name); throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
} }
if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses)) { if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses)) {
$this->subClasses[] = $className; $this->subClasses[] = $className;
} }
} }
}
/** /**
* Checks whether the class has a named query with the given query name. * Checks whether the class has a named query with the given query name.

View File

@ -5,7 +5,7 @@ namespace Doctrine\Tests\Models\CompositeKeyInheritance;
* @Entity * @Entity
* @InheritanceType("JOINED") * @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"child" = "JoinedChildClass",}) * @DiscriminatorMap({"child" = "JoinedChildClass", "root" = "JoinedRootClass"})
*/ */
class JoinedRootClass class JoinedRootClass
{ {

View File

@ -5,7 +5,7 @@ namespace Doctrine\Tests\Models\CompositeKeyInheritance;
* @Entity * @Entity
* @InheritanceType("SINGLE_TABLE") * @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"child" = "SingleChildClass",}) * @DiscriminatorMap({"child" = "SingleChildClass", "root" = "SingleRootClass"})
*/ */
class SingleRootClass class SingleRootClass
{ {

View File

@ -50,7 +50,7 @@ class DDC1113Test extends \Doctrine\Tests\OrmFunctionalTestCase
/** /**
* @Entity * @Entity
* @InheritanceType("SINGLE_TABLE") * @InheritanceType("SINGLE_TABLE")
* @DiscriminatorMap({"car" = "DDC1113Car", "bus" = "DDC1113Bus"}) * @DiscriminatorMap({"vehicle" = "DDC1113Vehicle", "car" = "DDC1113Car", "bus" = "DDC1113Bus"})
*/ */
class DDC1113Vehicle class DDC1113Vehicle
{ {

View File

@ -43,7 +43,7 @@ class DDC1454Picture extends DDC1454File
* @Entity * @Entity
* @InheritanceType("JOINED") * @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"picture" = "DDC1454Picture"}) * @DiscriminatorMap({"file" = "DDC1454File", "picture" = "DDC1454Picture"})
*/ */
class DDC1454File class DDC1454File
{ {

View File

@ -115,7 +115,7 @@ class DDC1509Picture
* @Entity * @Entity
* @InheritanceType("SINGLE_TABLE") * @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"file" = "DDC1509File"}) * @DiscriminatorMap({"abstractFile" = "DDC1509AbstractFile", "file" = "DDC1509File"})
*/ */
class DDC1509AbstractFile class DDC1509AbstractFile
{ {

View File

@ -33,7 +33,7 @@ class DDC1787Test extends \Doctrine\Tests\OrmFunctionalTestCase
* @Entity * @Entity
* @InheritanceType("JOINED") * @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"bar" = "DDC1787Bar"}) * @DiscriminatorMap({"bar" = "DDC1787Bar", "foo" = "DDC1787Foo"})
*/ */
class DDC1787Foo class DDC1787Foo
{ {

View File

@ -71,7 +71,8 @@ class DDC2012Test extends \Doctrine\Tests\OrmFunctionalTestCase
* @InheritanceType("JOINED") * @InheritanceType("JOINED")
* @DiscriminatorColumn(name="type_id", type="smallint") * @DiscriminatorColumn(name="type_id", type="smallint")
* @DiscriminatorMap({ * @DiscriminatorMap({
* 1 = "DDC2012ItemPerson" * 1 = "DDC2012ItemPerson",
* 2 = "DDC2012Item"
* }) * })
*/ */
class DDC2012Item class DDC2012Item

View File

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

View File

@ -54,6 +54,7 @@ class Journalist extends Participant
* @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({ * @DiscriminatorMap({
* "journalist" = "Journalist", * "journalist" = "Journalist",
* "participant" = "Participant",
* }) * })
*/ */
class Participant class Participant
@ -71,6 +72,7 @@ class Participant
* @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({ * @DiscriminatorMap({
* "profile" = "ProfileStatus", * "profile" = "ProfileStatus",
* "status" = "Status",
* }) * })
*/ */
class 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__;
}