diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index 701aee551..ff09210be 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -96,6 +96,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory $class->setIdGeneratorType($parent->generatorType); $this->addInheritedFields($class, $parent); $this->addInheritedRelations($class, $parent); + $this->addInheritedEmbeddedClasses($class, $parent); $class->setIdentifier($parent->identifier); $class->setVersioned($parent->isVersioned); $class->setVersionField($parent->versionField); @@ -141,7 +142,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory } foreach ($class->embeddedClasses as $property => $embeddableClass) { - $embeddableMetadata = $this->getMetadataFor($embeddableClass); + if (isset($embeddableClass['inherited'])) { + continue; + } + + $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); $class->inlineEmbeddable($property, $embeddableMetadata); } @@ -343,6 +348,20 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory } } + private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass) + { + foreach ($parentClass->embeddedClasses as $field => $embeddedClass) { + if ( ! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) { + $embeddedClass['inherited'] = $parentClass->name; + } + if ( ! isset($embeddedClass['declared'])) { + $embeddedClass['declared'] = $parentClass->name; + } + + $subClass->embeddedClasses[$field] = $embeddedClass; + } + } + /** * Adds inherited named queries to the subclass mapping. * diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 612574e90..3a4d080ab 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -899,10 +899,12 @@ class ClassMetadataInfo implements ClassMetadata foreach ($this->fieldMappings as $field => $mapping) { if (isset($mapping['declaredField'])) { + $declaringClass = isset($this->embeddedClasses[$field]['declared']) ? $this->embeddedClasses[$field]['declared'] : $this->name; + $this->reflFields[$field] = new ReflectionEmbeddedProperty( - $reflService->getAccessibleProperty($this->name, $mapping['declaredField']), - $reflService->getAccessibleProperty($this->embeddedClasses[$mapping['declaredField']], $mapping['originalField']), - $this->embeddedClasses[$mapping['declaredField']] + $reflService->getAccessibleProperty($declaringClass, $mapping['declaredField']), + $reflService->getAccessibleProperty($this->embeddedClasses[$mapping['declaredField']]['class'], $mapping['originalField']), + $this->embeddedClasses[$mapping['declaredField']]['class'] ); continue; } @@ -2110,6 +2112,11 @@ class ClassMetadataInfo implements ClassMetadata return isset($this->associationMappings[$fieldName]['inherited']); } + public function isInheritedEmbeddedClass($fieldName) + { + return isset($this->embeddedClasses[$fieldName]['inherited']); + } + /** * Sets the name of the primary table the class is mapped to. * @@ -3079,7 +3086,9 @@ class ClassMetadataInfo implements ClassMetadata { $this->assertFieldNotMapped($mapping['fieldName']); - $this->embeddedClasses[$mapping['fieldName']] = $this->fullyQualifiedClassName($mapping['class']); + $this->embeddedClasses[$mapping['fieldName']] = array( + 'class' => $this->fullyQualifiedClassName($mapping['class']) + ); } /** diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index b2437de23..e7893f33a 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -242,7 +242,9 @@ class AnnotationDriver extends AbstractAnnotationDriver || $metadata->isInheritedField($property->name) || - $metadata->isInheritedAssociation($property->name)) { + $metadata->isInheritedAssociation($property->name) + || + $metadata->isInheritedEmbeddedClass($property->name)) { continue; } diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php index bc02268c0..f82220a1f 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php @@ -15,6 +15,8 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_schemaTool->createSchema(array( $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93Person'), $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93Address'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93Vehicle'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93Car'), )); } catch(\Exception $e) { } @@ -146,6 +148,16 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->createQuery("SELECT p FROM " . __NAMESPACE__ . "\\DDC93Person p WHERE p.address.asdfasdf IS NULL") ->execute(); } + + public function testEmbeddableWithInheritance() + { + $car = new DDC93Car(new DDC93Address('Foo', '12345', 'Asdf')); + $this->_em->persist($car); + $this->_em->flush($car); + + $reloadedCar = $this->_em->find(__NAMESPACE__.'\\DDC93Car', $car->id); + $this->assertEquals($car, $reloadedCar); + } } /** @@ -171,6 +183,36 @@ class DDC93Person } } +/** + * @Entity + * + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name = "t", type = "string", length = 10) + * @DiscriminatorMap({ + * "v" = "Doctrine\Tests\ORM\Functional\DDC93Car", + * }) + */ +abstract class DDC93Vehicle +{ + /** @Id @GeneratedValue(strategy = "AUTO") @Column(type = "integer") */ + public $id; + + /** @Embedded(class = "DDC93Address") */ + public $address; + + public function __construct(DDC93Address $address) + { + $this->address = $address; + } +} + +/** + * @Entity + */ +class DDC93Car extends DDC93Vehicle +{ +} + /** * @Embeddable */