1
0
mirror of synced 2025-01-09 18:47:10 +03:00

Merge branch 'hotfix/#1196-inherit-mapped-superclass-indexes'

See DDC-3418
See DDC-3419

Close #1196
This commit is contained in:
Marco Pivetta 2014-11-27 19:10:57 +01:00
commit 9eae0d5ce8
2 changed files with 184 additions and 115 deletions

View File

@ -171,37 +171,43 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
}
}
if ($parent && $parent->isInheritanceTypeSingleTable()) {
$class->setPrimaryTable($parent->table);
}
if ($parent) {
if ($parent->isInheritanceTypeSingleTable()) {
$class->setPrimaryTable($parent->table);
}
if ($parent && $parent->cache) {
$class->cache = $parent->cache;
}
if ($parent) {
$this->addInheritedIndexes($class, $parent);
}
if ($parent && $parent->containsForeignIdentifier) {
$class->containsForeignIdentifier = true;
}
if ($parent->cache) {
$class->cache = $parent->cache;
}
if ($parent && !empty($parent->namedQueries)) {
$this->addInheritedNamedQueries($class, $parent);
}
if ($parent->containsForeignIdentifier) {
$class->containsForeignIdentifier = true;
}
if ($parent && !empty($parent->namedNativeQueries)) {
$this->addInheritedNamedNativeQueries($class, $parent);
}
if ( ! empty($parent->namedQueries)) {
$this->addInheritedNamedQueries($class, $parent);
}
if ($parent && !empty($parent->sqlResultSetMappings)) {
$this->addInheritedSqlResultSetMappings($class, $parent);
}
if ( ! empty($parent->namedNativeQueries)) {
$this->addInheritedNamedNativeQueries($class, $parent);
}
if ($parent && !empty($parent->entityListeners) && empty($class->entityListeners)) {
$class->entityListeners = $parent->entityListeners;
if ( ! empty($parent->sqlResultSetMappings)) {
$this->addInheritedSqlResultSetMappings($class, $parent);
}
if ( ! empty($parent->entityListeners) && empty($class->entityListeners)) {
$class->entityListeners = $parent->entityListeners;
}
}
$class->setParentClasses($nonSuperclassParents);
if ( $class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) {
if ($class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) {
$this->addDefaultDiscriminatorMap($class);
}
@ -415,6 +421,33 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
}
}
/**
* Copy the table indices from the parent class superclass to the child class
*
* @param ClassMetadata $subClass
* @param ClassMetadata $parentClass
*
* @return void
*/
private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass)
{
if (! $parentClass->isMappedSuperclass) {
return;
}
foreach (array('uniqueConstraints', 'indexes') as $indexType) {
if (isset($parentClass->table[$indexType])) {
foreach ($parentClass->table[$indexType] as $indexName => $index) {
if (isset($subClass->table[$indexType][$indexName])) {
continue; // Let the inheriting table override indices
}
$subClass->table[$indexType][$indexName] = $index;
}
}
}
}
/**
* Adds inherited named queries to the subclass mapping.
*

View File

@ -2,53 +2,61 @@
namespace Doctrine\Tests\ORM\Mapping;
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\Tests\Models\DDC869\DDC869Payment;
class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
{
private $_factory;
protected function setUp() {
$this->_factory = new ClassMetadataFactory();
$this->_factory->setEntityManager($this->_getTestEntityManager());
}
/**
* @var ClassMetadataFactory
*/
private $cmf;
/**
* @expectedException Doctrine\ORM\Mapping\MappingException
* {@inheritDoc}
*/
protected function setUp() {
$this->cmf = new ClassMetadataFactory();
$this->cmf->setEntityManager($this->_getTestEntityManager());
}
public function testGetMetadataForTransientClassThrowsException()
{
$this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\TransientBaseClass');
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
$this->cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\TransientBaseClass');
}
public function testGetMetadataForSubclassWithTransientBaseClass()
{
$class = $this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\EntitySubClass');
$class = $this->cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\EntitySubClass');
$this->assertTrue(empty($class->subClasses));
$this->assertTrue(empty($class->parentClasses));
$this->assertTrue(isset($class->fieldMappings['id']));
$this->assertTrue(isset($class->fieldMappings['name']));
$this->assertEmpty($class->subClasses);
$this->assertEmpty($class->parentClasses);
$this->assertArrayHasKey('id', $class->fieldMappings);
$this->assertArrayHasKey('name', $class->fieldMappings);
}
public function testGetMetadataForSubclassWithMappedSuperclass()
{
$class = $this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\EntitySubClass2');
$class = $this->cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\EntitySubClass2');
$this->assertTrue(empty($class->subClasses));
$this->assertTrue(empty($class->parentClasses));
$this->assertEmpty($class->subClasses);
$this->assertEmpty($class->parentClasses);
$this->assertTrue(isset($class->fieldMappings['mapped1']));
$this->assertTrue(isset($class->fieldMappings['mapped2']));
$this->assertTrue(isset($class->fieldMappings['id']));
$this->assertTrue(isset($class->fieldMappings['name']));
$this->assertArrayHasKey('mapped1', $class->fieldMappings);
$this->assertArrayHasKey('mapped2', $class->fieldMappings);
$this->assertArrayHasKey('id', $class->fieldMappings);
$this->assertArrayHasKey('name', $class->fieldMappings);
$this->assertFalse(isset($class->fieldMappings['mapped1']['inherited']));
$this->assertFalse(isset($class->fieldMappings['mapped2']['inherited']));
$this->assertFalse(isset($class->fieldMappings['transient']));
$this->assertArrayNotHasKey('inherited', $class->fieldMappings['mapped1']);
$this->assertArrayNotHasKey('inherited', $class->fieldMappings['mapped2']);
$this->assertArrayNotHasKey('transient', $class->fieldMappings);
$this->assertTrue(isset($class->associationMappings['mappedRelated1']));
$this->assertArrayHasKey('mappedRelated1', $class->associationMappings);
}
/**
@ -56,28 +64,28 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
*/
public function testGetMetadataForSubclassWithMappedSuperclassWithRepository()
{
$class = $this->_factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment');
$class = $this->cmf->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment');
$this->assertTrue(isset($class->fieldMappings['id']));
$this->assertTrue(isset($class->fieldMappings['value']));
$this->assertTrue(isset($class->fieldMappings['creditCardNumber']));
$this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
$this->assertArrayHasKey('id', $class->fieldMappings);
$this->assertArrayHasKey('value', $class->fieldMappings);
$this->assertArrayHasKey('creditCardNumber', $class->fieldMappings);
$this->assertEquals($class->customRepositoryClassName, 'Doctrine\Tests\Models\DDC869\DDC869PaymentRepository');
$class = $this->_factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869ChequePayment');
$class = $this->cmf->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869ChequePayment');
$this->assertTrue(isset($class->fieldMappings['id']));
$this->assertTrue(isset($class->fieldMappings['value']));
$this->assertTrue(isset($class->fieldMappings['serialNumber']));
$this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
$this->assertArrayHasKey('id', $class->fieldMappings);
$this->assertArrayHasKey('value', $class->fieldMappings);
$this->assertArrayHasKey('serialNumber', $class->fieldMappings);
$this->assertEquals($class->customRepositoryClassName, 'Doctrine\Tests\Models\DDC869\DDC869PaymentRepository');
// override repositoryClass
$class = $this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\SubclassWithRepository');
$class = $this->cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\SubclassWithRepository');
$this->assertTrue(isset($class->fieldMappings['id']));
$this->assertTrue(isset($class->fieldMappings['value']));
$this->assertEquals($class->customRepositoryClassName, "Doctrine\ORM\EntityRepository");
$this->assertArrayHasKey('id', $class->fieldMappings);
$this->assertArrayHasKey('value', $class->fieldMappings);
$this->assertEquals($class->customRepositoryClassName, 'Doctrine\ORM\EntityRepository');
}
/**
@ -86,14 +94,14 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
public function testSerializationWithPrivateFieldsFromMappedSuperclass()
{
$class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\EntitySubClass2');
$class = $this->cmf->getMetadataFor(__NAMESPACE__ . '\\EntitySubClass2');
$class2 = unserialize(serialize($class));
$class2->wakeupReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$class2->wakeupReflection(new RuntimeReflectionService);
$this->assertTrue(isset($class2->reflFields['mapped1']));
$this->assertTrue(isset($class2->reflFields['mapped2']));
$this->assertTrue(isset($class2->reflFields['mappedRelated1']));
$this->assertArrayHasKey('mapped1', $class2->reflFields);
$this->assertArrayHasKey('mapped2', $class2->reflFields);
$this->assertArrayHasKey('mappedRelated1', $class2->reflFields);
}
/**
@ -101,11 +109,11 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
*/
public function testUnmappedSuperclassInHierarchy()
{
$class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\HierarchyD');
$class = $this->cmf->getMetadataFor(__NAMESPACE__ . '\\HierarchyD');
$this->assertTrue(isset($class->fieldMappings['id']));
$this->assertTrue(isset($class->fieldMappings['a']));
$this->assertTrue(isset($class->fieldMappings['d']));
$this->assertArrayHasKey('id', $class->fieldMappings);
$this->assertArrayHasKey('a', $class->fieldMappings);
$this->assertArrayHasKey('d', $class->fieldMappings);
}
/**
@ -113,9 +121,14 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
*/
public function testUnmappedEntityInHierarchy()
{
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException', "Entity 'Doctrine\Tests\ORM\Mapping\HierarchyBEntity' has to be part of the discriminator map of 'Doctrine\Tests\ORM\Mapping\HierarchyBase' to be properly mapped in the inheritance hierarchy. Alternatively you can make 'Doctrine\Tests\ORM\Mapping\HierarchyBEntity' an abstract class to avoid this exception from occurring.");
$this->setExpectedException(
'Doctrine\ORM\Mapping\MappingException',
'Entity \'Doctrine\Tests\ORM\Mapping\HierarchyBEntity\' has to be part of the discriminator map'
. ' of \'Doctrine\Tests\ORM\Mapping\HierarchyBase\' to be properly mapped in the inheritance hierarchy.'
. ' Alternatively you can make \'Doctrine\Tests\ORM\Mapping\HierarchyBEntity\' an abstract class to'
. ' avoid this exception from occurring.');
$class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\HierarchyE');
$this->cmf->getMetadataFor(__NAMESPACE__ . '\\HierarchyE');
}
/**
@ -124,9 +137,9 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
*/
public function testMappedSuperclassWithId()
{
$class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\SuperclassEntity');
$class = $this->cmf->getMetadataFor(__NAMESPACE__ . '\\SuperclassEntity');
$this->assertTrue(isset($class->fieldMappings['id']));
$this->assertArrayHasKey('id', $class->fieldMappings);
}
/**
@ -135,11 +148,14 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
*/
public function testGeneratedValueFromMappedSuperclass()
{
$class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\SuperclassEntity');
$class = $this->cmf->getMetadataFor(__NAMESPACE__ . '\\SuperclassEntity');
/* @var $class ClassMetadataInfo */
$this->assertInstanceOf('Doctrine\ORM\Id\SequenceGenerator', $class->idGenerator);
$this->assertEquals(array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'), $class->sequenceGeneratorDefinition);
$this->assertEquals(
array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'),
$class->sequenceGeneratorDefinition
);
}
/**
@ -148,11 +164,14 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
*/
public function testSequenceDefinitionInHierarchyWithSandwichMappedSuperclass()
{
$class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\HierarchyD');
$class = $this->cmf->getMetadataFor(__NAMESPACE__ . '\\HierarchyD');
/* @var $class ClassMetadataInfo */
$this->assertInstanceOf('Doctrine\ORM\Id\SequenceGenerator', $class->idGenerator);
$this->assertEquals(array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'), $class->sequenceGeneratorDefinition);
$this->assertEquals(
array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'),
$class->sequenceGeneratorDefinition
);
}
/**
@ -161,11 +180,30 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
*/
public function testMultipleMappedSuperclasses()
{
$class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\MediumSuperclassEntity');
$class = $this->cmf->getMetadataFor(__NAMESPACE__ . '\\MediumSuperclassEntity');
/* @var $class ClassMetadataInfo */
$this->assertInstanceOf('Doctrine\ORM\Id\SequenceGenerator', $class->idGenerator);
$this->assertEquals(array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'), $class->sequenceGeneratorDefinition);
$this->assertEquals(
array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'),
$class->sequenceGeneratorDefinition
);
}
/**
* Ensure indexes are inherited from the mapped superclass.
*
* @group DDC-3418
*/
public function testMappedSuperclassIndex()
{
$class = $this->cmf->getMetadataFor(__NAMESPACE__ . '\\EntityIndexSubClass');
/* @var $class ClassMetadataInfo */
$this->assertArrayHasKey('mapped1', $class->fieldMappings);
$this->assertArrayHasKey('IDX_NAME_INDEX', $class->table['uniqueConstraints']);
$this->assertArrayHasKey('IDX_MAPPED1_INDEX', $class->table['uniqueConstraints']);
$this->assertArrayHasKey('IDX_MAPPED2_INDEX', $class->table['indexes']);
}
}
@ -206,6 +244,29 @@ class EntitySubClass2 extends MappedSuperclassBase {
private $name;
}
/**
* @MappedSuperclass
* @Table(
* uniqueConstraints={@UniqueConstraint(name="IDX_MAPPED1_INDEX",columns={"mapped1"})},
* indexes={@Index(name="IDX_MAPPED2_INDEX", columns={"mapped2"})}
* )
*/
class MappedSuperclassBaseIndex {
/** @Column(type="string") */
private $mapped1;
/** @Column(type="string") */
private $mapped2;
}
/** @Entity @Table(uniqueConstraints={@UniqueConstraint(name="IDX_NAME_INDEX",columns={"name"})}) */
class EntityIndexSubClass extends MappedSuperclassBaseIndex
{
/** @Id @Column(type="integer") */
private $id;
/** @Column(type="string") */
private $name;
}
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
@ -226,92 +287,67 @@ abstract class HierarchyBase
public $id;
}
/**
* @MappedSuperclass
*/
/** @MappedSuperclass */
abstract class HierarchyASuperclass extends HierarchyBase
{
/** @Column(type="string") */
public $a;
}
/**
* @Entity
*/
/** @Entity */
class HierarchyBEntity extends HierarchyBase
{
/** @Column(type="string") */
public $b;
}
/**
* @Entity
*/
/** @Entity */
class HierarchyC extends HierarchyBase
{
/** @Column(type="string") */
public $c;
}
/**
* @Entity
*/
/** @Entity */
class HierarchyD extends HierarchyASuperclass
{
/** @Column(type="string") */
public $d;
}
/**
* @Entity
*/
/** @Entity */
class HierarchyE extends HierarchyBEntity
{
/** @Column(type="string") */
public $e;
}
/**
* @Entity
*/
/** @Entity */
class SuperclassEntity extends SuperclassBase
{
}
/**
* @MappedSuperclass
*/
/** @MappedSuperclass */
abstract class SuperclassBase
{
/**
* @Column(type="integer") @Id @GeneratedValue(strategy="SEQUENCE")
* @SequenceGenerator(sequenceName="foo", initialValue=10)
* @var int
*/
public $id;
}
/**
* @MappedSuperclass
*/
/** @MappedSuperclass */
abstract class MediumSuperclassBase extends SuperclassBase
{
}
/**
* @Entity
*/
/** @Entity */
class MediumSuperclassEntity extends MediumSuperclassBase
{
}
/**
* @Entity(repositoryClass = "Doctrine\ORM\EntityRepository")
*/
class SubclassWithRepository extends \Doctrine\Tests\Models\DDC869\DDC869Payment
/** @Entity(repositoryClass = "Doctrine\ORM\EntityRepository") */
class SubclassWithRepository extends DDC869Payment
{
}