1
0
mirror of synced 2025-01-18 06:21:40 +03:00

[DDC-1542] - Inheritance: Added default discriminator map (only annotations yet)

This commit is contained in:
comfortablynumb 2011-12-16 20:19:27 -03:00 committed by Benjamin Eberlei
parent 6d5f15e708
commit f0db9a842d
5 changed files with 165 additions and 4 deletions

View File

@ -164,13 +164,11 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
if (($cached = $this->fetchMetadataFromCache($realClassName)) !== false) {
$this->loadedMetadata[$realClassName] = $cached;
} else {
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
$this->cacheDriver->save(
"$loadedClassName\$CLASSMETADATA", $this->loadedMetadata[$loadedClassName], null
);
$this->cacheMetadata($loadedClassName, $this->loadedMetadata[$loadedClassName]);
}
}
} else {
@ -319,6 +317,11 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$class->setParentClasses($visited);
// Calculate Discriminator Map if needed and if no discriminator map is set
if ($class->isInheritanceTypeJoined() && empty($class->discriminatorMap)) {
$this->addDefaultDiscriminatorMap($class);
}
if ($this->evm->hasListeners(Events::loadClassMetadata)) {
$eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class, $this->em);
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
@ -388,6 +391,89 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
return new ClassMetadata($className);
}
/**
* Adds a default discriminator map if no one is given
*
* @param \Doctrine\ORM\Mapping\ClassMetadata $class
*/
private function addDefaultDiscriminatorMap(ClassMetadata $class)
{
$allClasses = $this->driver->getAllClassNames();
$subClassesMetadata = array();
$fqcn = $class->getName();
$map = array(str_replace('\\', '.', $fqcn) => $fqcn);
foreach ($allClasses as $c) {
if (is_subclass_of($c, $fqcn)) {
if (isset($this->loadedMetadata[$c])) {
$subClassMetadata = $this->loadedMetadata[$c];
} else {
$subClassMetadata = $this->newClassMetadataInstance($c);
$this->driver->loadMetadataForClass($c, $subClassMetadata);
}
if (!$subClassMetadata->isMappedSuperclass) {
$map[str_replace('\\', '.', $c)] = $c;
$subClassesMetadata[$c] = $subClassMetadata;
}
}
}
$class->setDiscriminatorMap($map);
// Now we set the discriminator map for the subclasses already loaded
foreach ($subClassesMetadata as $subClassFqcn => $subClassMetadata) {
$subClassMetadata->setDiscriminatorMap($map);
// We need to overwrite the cached version of the metadata, because
// it was cached without the discriminator map
if ($this->cacheDriver && $this->cacheContainsMetadata($subClassFqcn)) {
// If subclass metadata is not already loaded, it's incomplete so
// we reload it again from cache
if (!isset($this->loadedMetadata[$subClassFqcn])) {
$subClassMetadata = $this->fetchMetadataFromCache($subClassFqcn);
$subClassMetadata->setDiscriminatorMap($map);
}
$this->cacheMetadata($subClassFqcn, $subClassMetadata);
}
}
}
/**
* Cache the metadata
*
* @param $className
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata
*/
private function cacheMetadata($className, ClassMetadata $metadata)
{
$this->cacheDriver->save(
"$className\$CLASSMETADATA", $metadata, null
);
}
/**
* Verify if metadata is cached
*
* @param $className
* @return bool
*/
private function cacheContainsMetadata($className)
{
return $this->cacheDriver->contains("$className\$CLASSMETADATA");
}
/**
* Fetch metadata from cache
*
* @param $className
*/
private function fetchMetadataFromCache($className)
{
return $this->cacheDriver->fetch("$className\$CLASSMETADATA");
}
/**
* Adds inherited fields to the subclass mapping.
*

View File

@ -0,0 +1,10 @@
<?php
namespace Doctrine\Tests\Models\JoinedInheritanceType;
/**
* @Entity
*/
class AnotherChildClass extends ChildClass
{
}

View File

@ -0,0 +1,10 @@
<?php
namespace Doctrine\Tests\Models\JoinedInheritanceType;
/**
* @MappedSuperclass
*/
abstract class ChildClass extends RootClass
{
}

View File

@ -0,0 +1,16 @@
<?php
namespace Doctrine\Tests\Models\JoinedInheritanceType;
/**
* @Entity
* @InheritanceType("JOINED")
*/
class RootClass
{
/**
* @Column(type="integer")
* @Id @GeneratedValue
*/
public $id;
}

View File

@ -127,6 +127,45 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($em->getMetadataFactory()->isTransient('CMS:CmsUser'));
$this->assertFalse($em->getMetadataFactory()->isTransient('CMS:CmsArticle'));
}
public function testAddDefaultDiscriminatorMap()
{
$cmf = new ClassMetadataFactory();
$driver = $this->createAnnotationDriver(array(__DIR__ . '/../../Models/JoinedInheritanceType/'));
$em = $this->_createEntityManager($driver);
$cmf->setEntityManager($em);
$rootMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\RootClass');
$childMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\ChildClass');
$anotherChildMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\AnotherChildClass');
$rootDiscriminatorMap = $rootMetadata->discriminatorMap;
$childDiscriminatorMap = $childMetadata->discriminatorMap;
$anotherChildDiscriminatorMap = $anotherChildMetadata->discriminatorMap;
$rootClass = 'Doctrine\Tests\Models\JoinedInheritanceType\RootClass';
$childClass = 'Doctrine\Tests\Models\JoinedInheritanceType\ChildClass';
$anotherChildClass = 'Doctrine\Tests\Models\JoinedInheritanceType\AnotherChildClass';
$rootClassKey = array_search($rootClass, $rootDiscriminatorMap);
$childClassKey = array_search($childClass, $rootDiscriminatorMap);
$anotherChildClassKey = array_search($anotherChildClass, $rootDiscriminatorMap);
$this->assertEquals(str_replace('\\', '.', $rootClass), $rootClassKey);
$this->assertFalse($childClassKey);
$this->assertEquals(str_replace('\\', '.', $anotherChildClassKey), $anotherChildClassKey);
$this->assertEquals($childDiscriminatorMap, $rootDiscriminatorMap);
$this->assertEquals($anotherChildDiscriminatorMap, $rootDiscriminatorMap);
// ClassMetadataFactory::addDefaultDiscriminatorMap shouldn't be called again, because the
// discriminator map is already cached
$cmf = $this->getMock('Doctrine\ORM\Mapping\ClassMetadataFactory', array('addDefaultDiscriminatorMap'));
$cmf->setEntityManager($em);
$cmf->expects($this->never())
->method('addDefaultDiscriminatorMap');
$rootMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\RootClass');
}
protected function _createEntityManager($metadataDriver)
{