Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@doctrinebot
Created December 13, 2015 18:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doctrinebot/bb26bf1d944b4e23b1d6 to your computer and use it in GitHub Desktop.
Save doctrinebot/bb26bf1d944b4e23b1d6 to your computer and use it in GitHub Desktop.
Attachments to Doctrine Jira Issue DDC-132 - https://github.com/doctrine/doctrine2/issues/1934
Index: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
===================================================================
--- lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php (revision 6700)
+++ lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php (working copy)
@@ -108,11 +108,14 @@
if (($cached = $this->_cacheDriver->fetch($cacheKey)) !== false) {
$this->_loadedMetadata[$className] = $cached;
} else {
- $this->_loadMetadata($className);
- $this->_cacheDriver->save($cacheKey, $this->_loadedMetadata[$className], null);
+ $classes = $this->_loadMetadataHierarchy($className);
+ foreach ($classes as $class) {
+ $cacheKey = "$class\$CLASSMETADATA";
+ $this->_cacheDriver->save($cacheKey, $this->_loadedMetadata[$class], null);
+ }
}
} else {
- $this->_loadMetadata($className);
+ $this->_loadMetadataHierarchy($className);
}
}
@@ -141,18 +144,85 @@
{
$this->_loadedMetadata[$className] = $class;
}
-
+
+ protected function _loadMetadata($className, ClassMetadata $parent = null, $parentClasses = array())
+ {
+ $class = $this->_newClassMetadataInstance($className);
+
+ if ($parent) {
+ $class->setInheritanceType($parent->inheritanceType);
+ $class->setDiscriminatorColumn($parent->discriminatorColumn);
+ $class->setIdGeneratorType($parent->generatorType);
+ $this->_addInheritedFields($class, $parent);
+ $this->_addInheritedRelations($class, $parent);
+ $class->setIdentifier($parent->identifier);
+ $class->setVersioned($parent->isVersioned);
+ $class->setVersionField($parent->versionField);
+ $class->setDiscriminatorMap($parent->discriminatorMap);
+ $class->setResultColumnNames($parent->resultColumnNames);
+ }
+
+ // Invoke driver
+ $this->_driver->loadMetadataForClass($className, $class);
+
+ // Verify & complete identifier mapping
+ if ( ! $class->identifier && ! $class->isMappedSuperclass) {
+ throw MappingException::identifierRequired($className);
+ }
+ if ($parent && ! $parent->isMappedSuperclass) {
+ if ($parent->isIdGeneratorSequence()) {
+ $class->setSequenceGeneratorDefinition($parent->getSequenceGeneratorDefinition());
+ } else if ($parent->isIdGeneratorTable()) {
+ $class->getTableGeneratorDefinition($parent->getTableGeneratorDefinition());
+ }
+ if ($generatorType = $parent->generatorType) {
+ $class->setIdGeneratorType($generatorType);
+ }
+ if ($idGenerator = $parent->getIdGenerator()) {
+ $class->setIdGenerator($idGenerator);
+ }
+ } else {
+ $this->_completeIdGeneratorMapping($class);
+ }
+
+ if ($parent && $parent->isInheritanceTypeSingleTable()) {
+ $class->setTableName($parent->getTableName());
+ }
+
+ $class->setParentClasses($parentClasses);
+
+ if ($this->_evm->hasListeners(Events::loadClassMetadata)) {
+ $eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class);
+ $this->_evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
+ }
+
+ if ( ! $class->isMappedSuperclass) {
+ $this->_generateStaticSql($class);
+ }
+
+ if ($parent) {
+ foreach ($parentClasses as $parentClassName) {
+ $parentClass = $this->_loadedMetadata[$parentClassName];
+ $parentClass->setResultColumnNames(array_merge($parentClass->resultColumnNames, $class->resultColumnNames));
+ }
+ }
+
+ $this->_loadedMetadata[$className] = $class;
+
+ return $class;
+ }
+
/**
- * Loads the metadata of the class in question and all it's ancestors whose metadata
- * is still not loaded.
+ * Loads the metadata of the class in question and all it's ancestors and children
+ * whose metadata is still not loaded.
*
- * @param string $name The name of the class for which the metadata should get loaded.
+ * @param string $className The name of the class for which the metadata should get loaded.
* @param array $tables The metadata collection to which the loaded metadata is added.
*/
- protected function _loadMetadata($name)
+ protected function _loadMetadataHierarchy($className)
{
// Collect parent classes, ignoring transient (not-mapped) classes.
- $parentClass = $name;
+ $parentClass = $className;
$parentClasses = array();
while ($parentClass = get_parent_class($parentClass)) {
if ( ! $this->_driver->isTransient($parentClass)) {
@@ -160,88 +230,34 @@
}
}
$parentClasses = array_reverse($parentClasses);
- $parentClasses[] = $name;
+ $parentClasses[] = $className;
// Move down the hierarchy of parent classes, starting from the topmost class
$parent = null;
$visited = array();
- foreach ($parentClasses as $className) {
- if (isset($this->_loadedMetadata[$className])) {
- $parent = $this->_loadedMetadata[$className];
+ foreach ($parentClasses as $parentClass) {
+ if (isset($this->_loadedMetadata[$parentClass])) {
+ $parent = $this->_loadedMetadata[$parentClass];
if ( ! $parent->isMappedSuperclass) {
- array_unshift($visited, $className);
+ array_unshift($visited, $parentClass);
}
continue;
}
-
- $class = $this->_newClassMetadataInstance($className);
- if ($parent) {
- $class->setInheritanceType($parent->inheritanceType);
- $class->setDiscriminatorColumn($parent->discriminatorColumn);
- $class->setIdGeneratorType($parent->generatorType);
- $this->_addInheritedFields($class, $parent);
- $this->_addInheritedRelations($class, $parent);
- $class->setIdentifier($parent->identifier);
- $class->setVersioned($parent->isVersioned);
- $class->setVersionField($parent->versionField);
- $class->setDiscriminatorMap($parent->discriminatorMap);
- $class->setResultColumnNames($parent->resultColumnNames);
- }
+ $class = $this->_loadMetadata($parentClass, $parent, $visited);
- // Invoke driver
- $this->_driver->loadMetadataForClass($className, $class);
-
- // Verify & complete identifier mapping
- if ( ! $class->identifier && ! $class->isMappedSuperclass) {
- throw MappingException::identifierRequired($className);
+ foreach ($class->subClasses as $subClass) {
+ $this->_loadMetadataHierarchy($subClass);
}
- if ($parent && ! $parent->isMappedSuperclass) {
- if ($parent->isIdGeneratorSequence()) {
- $class->setSequenceGeneratorDefinition($parent->getSequenceGeneratorDefinition());
- } else if ($parent->isIdGeneratorTable()) {
- $class->getTableGeneratorDefinition($parent->getTableGeneratorDefinition());
- }
- if ($generatorType = $parent->generatorType) {
- $class->setIdGeneratorType($generatorType);
- }
- if ($idGenerator = $parent->getIdGenerator()) {
- $class->setIdGenerator($idGenerator);
- }
- } else {
- $this->_completeIdGeneratorMapping($class);
- }
-
- if ($parent && $parent->isInheritanceTypeSingleTable()) {
- $class->setTableName($parent->getTableName());
- }
- $class->setParentClasses($visited);
+ $parent = $class;
- if ($this->_evm->hasListeners(Events::loadClassMetadata)) {
- $eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class);
- $this->_evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
- }
-
if ( ! $class->isMappedSuperclass) {
- $this->_generateStaticSql($class);
+ array_unshift($visited, $parentClass);
}
-
- if ($parent) {
- foreach ($visited as $parentClassName) {
- $parentClass = $this->_loadedMetadata[$parentClassName];
- $parentClass->setResultColumnNames(array_merge($parentClass->resultColumnNames, $class->resultColumnNames));
- }
- }
-
- $this->_loadedMetadata[$className] = $class;
-
- $parent = $class;
-
- if ( ! $class->isMappedSuperclass) {
- array_unshift($visited, $className);
- }
}
+
+ return $visited;
}
/**
Index: tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php
===================================================================
--- tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php (revision 6700)
+++ tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php (working copy)
@@ -14,6 +14,50 @@
class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
{
+ public function testClassHierarchyLoaded()
+ {
+ $reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache);
+ $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
+ $driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader);
+ $em = $this->_createEntityManager($driver);
+ $cmf = new \Doctrine\ORM\Mapping\ClassMetadataFactory($em);
+
+ $classA = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassA');
+ $this->assertTrue($cmf->hasMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassA'));
+ $this->assertTrue($cmf->hasMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassB'));
+ $this->assertTrue($cmf->hasMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassC'));
+ $this->assertTrue($cmf->hasMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassD'));
+
+ $classA = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassA');
+ $classB = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassB');
+ $classC = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassC');
+ $classD = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\HierarchyTestClassD');
+
+ /**
+ * The resultColumNames are not correct currently.
+ * It does not cause problems yet but they are for sure wrong
+ */
+
+ /*
+ $aResultColumnNames = array(
+ 'id' => 'id',
+ 'a' => 'a',
+ 'b' => 'b',
+ 'c' => 'c'
+ );
+ $this->assertEquals($aResultColumnNames, $classA->resultColumnNames);
+
+ $bResultColumnNames = array();
+ $this->assertEquals($bResultColumnNames, $classB->resultColumnNames);
+
+ $cResultColumnNames = array();
+ $this->assertEquals($cResultColumnNames, $classC->resultColumnNames);
+
+ $dResultColumnNames = array();
+ $this->assertEquals($dResultColumnNames, $classD->resultColumnNames);
+ */
+ }
+
public function testGetMetadataForSingleClass()
{
$mockDriver = new MetadataDriverMock();
@@ -130,3 +174,77 @@
private $other;
private $association;
}
+
+/**
+ * @Entity
+ * @InheritanceType("JOINED")
+ * @DiscriminatorColumn(name="discr", type="string")
+ * @DiscriminatorMap({"b" = "HierarchyTestClassB", "c" = "HierarchyTestClassC"})
+ */
+class HierarchyTestClassA
+{
+ /**
+ * @Id @Column(type="integer")
+ * @GeneratedValue(strategy="AUTO")
+ */
+ private $id;
+
+ /**
+ * @Column(type="string", length=50)
+ */
+ private $a;
+}
+
+/**
+ * @Entity
+ */
+class HierarchyTestClassB extends HierarchyTestClassA
+{
+ /**
+ * @Id @Column(type="integer")
+ * @GeneratedValue(strategy="AUTO")
+ */
+ private $id;
+
+ /**
+ * @Column(type="string", length=50)
+ */
+ private $b;
+}
+
+/**
+ * @Entity
+ * @InheritanceType("JOINED")
+ * @DiscriminatorColumn(name="discr", type="string")
+ * @DiscriminatorMap({"d" = "HierarchyTestClassD"})
+ */
+class HierarchyTestClassC extends HierarchyTestClassA
+{
+ /**
+ * @Id @Column(type="integer")
+ * @GeneratedValue(strategy="AUTO")
+ */
+ private $id;
+
+ /**
+ * @Column(type="string", length=50)
+ */
+ private $c;
+}
+
+/**
+ * @Entity
+ */
+class HierarchyTestClassD extends HierarchyTestClassC
+{
+ /**
+ * @Id @Column(type="integer")
+ * @GeneratedValue(strategy="AUTO")
+ */
+ private $id;
+
+ /**
+ * @Column(type="string", length=50)
+ */
+ private $d;
+}
\ No newline at end of file
Index: tests/Doctrine/Tests/TestUtil.php
===================================================================
--- tests/Doctrine/Tests/TestUtil.php (revision 6700)
+++ tests/Doctrine/Tests/TestUtil.php (working copy)
@@ -56,7 +56,7 @@
// Connect to tmpdb in order to drop and create the real test db.
$tmpConn = \Doctrine\DBAL\DriverManager::getConnection($tmpDbParams);
$realConn = \Doctrine\DBAL\DriverManager::getConnection($realDbParams);
-
+
$dbname = $realConn->getDatabase();
$realConn->close();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment