Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f0db9a8

Browse files
comfortablynumbbeberlei
authored andcommitted
[DDC-1542] - Inheritance: Added default discriminator map (only annotations yet)
1 parent 6d5f15e commit f0db9a8

5 files changed

Lines changed: 165 additions & 4 deletions

File tree

lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,11 @@ public function getMetadataFor($className)
164164
}
165165

166166
if ($this->cacheDriver) {
167-
if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
167+
if (($cached = $this->fetchMetadataFromCache($realClassName)) !== false) {
168168
$this->loadedMetadata[$realClassName] = $cached;
169169
} else {
170170
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
171-
$this->cacheDriver->save(
172-
"$loadedClassName\$CLASSMETADATA", $this->loadedMetadata[$loadedClassName], null
173-
);
171+
$this->cacheMetadata($loadedClassName, $this->loadedMetadata[$loadedClassName]);
174172
}
175173
}
176174
} else {
@@ -319,6 +317,11 @@ protected function loadMetadata($name)
319317

320318
$class->setParentClasses($visited);
321319

320+
// Calculate Discriminator Map if needed and if no discriminator map is set
321+
if ($class->isInheritanceTypeJoined() && empty($class->discriminatorMap)) {
322+
$this->addDefaultDiscriminatorMap($class);
323+
}
324+
322325
if ($this->evm->hasListeners(Events::loadClassMetadata)) {
323326
$eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class, $this->em);
324327
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
@@ -388,6 +391,89 @@ protected function newClassMetadataInstance($className)
388391
return new ClassMetadata($className);
389392
}
390393

394+
/**
395+
* Adds a default discriminator map if no one is given
396+
*
397+
* @param \Doctrine\ORM\Mapping\ClassMetadata $class
398+
*/
399+
private function addDefaultDiscriminatorMap(ClassMetadata $class)
400+
{
401+
$allClasses = $this->driver->getAllClassNames();
402+
$subClassesMetadata = array();
403+
$fqcn = $class->getName();
404+
$map = array(str_replace('\\', '.', $fqcn) => $fqcn);
405+
406+
foreach ($allClasses as $c) {
407+
if (is_subclass_of($c, $fqcn)) {
408+
if (isset($this->loadedMetadata[$c])) {
409+
$subClassMetadata = $this->loadedMetadata[$c];
410+
} else {
411+
$subClassMetadata = $this->newClassMetadataInstance($c);
412+
$this->driver->loadMetadataForClass($c, $subClassMetadata);
413+
}
414+
415+
if (!$subClassMetadata->isMappedSuperclass) {
416+
$map[str_replace('\\', '.', $c)] = $c;
417+
$subClassesMetadata[$c] = $subClassMetadata;
418+
}
419+
}
420+
}
421+
422+
$class->setDiscriminatorMap($map);
423+
424+
// Now we set the discriminator map for the subclasses already loaded
425+
foreach ($subClassesMetadata as $subClassFqcn => $subClassMetadata) {
426+
$subClassMetadata->setDiscriminatorMap($map);
427+
428+
// We need to overwrite the cached version of the metadata, because
429+
// it was cached without the discriminator map
430+
if ($this->cacheDriver && $this->cacheContainsMetadata($subClassFqcn)) {
431+
// If subclass metadata is not already loaded, it's incomplete so
432+
// we reload it again from cache
433+
if (!isset($this->loadedMetadata[$subClassFqcn])) {
434+
$subClassMetadata = $this->fetchMetadataFromCache($subClassFqcn);
435+
$subClassMetadata->setDiscriminatorMap($map);
436+
}
437+
438+
$this->cacheMetadata($subClassFqcn, $subClassMetadata);
439+
}
440+
}
441+
}
442+
443+
/**
444+
* Cache the metadata
445+
*
446+
* @param $className
447+
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata
448+
*/
449+
private function cacheMetadata($className, ClassMetadata $metadata)
450+
{
451+
$this->cacheDriver->save(
452+
"$className\$CLASSMETADATA", $metadata, null
453+
);
454+
}
455+
456+
/**
457+
* Verify if metadata is cached
458+
*
459+
* @param $className
460+
* @return bool
461+
*/
462+
private function cacheContainsMetadata($className)
463+
{
464+
return $this->cacheDriver->contains("$className\$CLASSMETADATA");
465+
}
466+
467+
/**
468+
* Fetch metadata from cache
469+
*
470+
* @param $className
471+
*/
472+
private function fetchMetadataFromCache($className)
473+
{
474+
return $this->cacheDriver->fetch("$className\$CLASSMETADATA");
475+
}
476+
391477
/**
392478
* Adds inherited fields to the subclass mapping.
393479
*
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Doctrine\Tests\Models\JoinedInheritanceType;
4+
5+
/**
6+
* @Entity
7+
*/
8+
class AnotherChildClass extends ChildClass
9+
{
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Doctrine\Tests\Models\JoinedInheritanceType;
4+
5+
/**
6+
* @MappedSuperclass
7+
*/
8+
abstract class ChildClass extends RootClass
9+
{
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Doctrine\Tests\Models\JoinedInheritanceType;
4+
5+
/**
6+
* @Entity
7+
* @InheritanceType("JOINED")
8+
*/
9+
class RootClass
10+
{
11+
/**
12+
* @Column(type="integer")
13+
* @Id @GeneratedValue
14+
*/
15+
public $id;
16+
}

tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,45 @@ public function testIsTransientEntityNamespace()
127127
$this->assertTrue($em->getMetadataFactory()->isTransient('CMS:CmsUser'));
128128
$this->assertFalse($em->getMetadataFactory()->isTransient('CMS:CmsArticle'));
129129
}
130+
131+
public function testAddDefaultDiscriminatorMap()
132+
{
133+
$cmf = new ClassMetadataFactory();
134+
$driver = $this->createAnnotationDriver(array(__DIR__ . '/../../Models/JoinedInheritanceType/'));
135+
$em = $this->_createEntityManager($driver);
136+
$cmf->setEntityManager($em);
137+
138+
$rootMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\RootClass');
139+
$childMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\ChildClass');
140+
$anotherChildMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\AnotherChildClass');
141+
$rootDiscriminatorMap = $rootMetadata->discriminatorMap;
142+
$childDiscriminatorMap = $childMetadata->discriminatorMap;
143+
$anotherChildDiscriminatorMap = $anotherChildMetadata->discriminatorMap;
144+
145+
$rootClass = 'Doctrine\Tests\Models\JoinedInheritanceType\RootClass';
146+
$childClass = 'Doctrine\Tests\Models\JoinedInheritanceType\ChildClass';
147+
$anotherChildClass = 'Doctrine\Tests\Models\JoinedInheritanceType\AnotherChildClass';
148+
149+
$rootClassKey = array_search($rootClass, $rootDiscriminatorMap);
150+
$childClassKey = array_search($childClass, $rootDiscriminatorMap);
151+
$anotherChildClassKey = array_search($anotherChildClass, $rootDiscriminatorMap);
152+
153+
$this->assertEquals(str_replace('\\', '.', $rootClass), $rootClassKey);
154+
$this->assertFalse($childClassKey);
155+
$this->assertEquals(str_replace('\\', '.', $anotherChildClassKey), $anotherChildClassKey);
156+
157+
$this->assertEquals($childDiscriminatorMap, $rootDiscriminatorMap);
158+
$this->assertEquals($anotherChildDiscriminatorMap, $rootDiscriminatorMap);
159+
160+
// ClassMetadataFactory::addDefaultDiscriminatorMap shouldn't be called again, because the
161+
// discriminator map is already cached
162+
$cmf = $this->getMock('Doctrine\ORM\Mapping\ClassMetadataFactory', array('addDefaultDiscriminatorMap'));
163+
$cmf->setEntityManager($em);
164+
$cmf->expects($this->never())
165+
->method('addDefaultDiscriminatorMap');
166+
167+
$rootMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\RootClass');
168+
}
130169

131170
protected function _createEntityManager($metadataDriver)
132171
{

0 commit comments

Comments
 (0)