diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index cbb8c0cc9..876f1ce57 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -64,6 +64,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory */ private $evm; + /** + * @var array + */ + private $embeddablesActiveNesting = array(); + /** * @param EntityManager $em */ @@ -148,10 +153,12 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory continue; } - if ($embeddableClass['class'] === $class->name) { + if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) { throw MappingException::infiniteEmbeddableNesting($class->name, $property); } + $this->embeddablesActiveNesting[$class->name] = true; + $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); if ($embeddableMetadata->isEmbeddedClass) { @@ -159,6 +166,8 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory } $class->inlineEmbeddable($property, $embeddableMetadata); + + unset($this->embeddablesActiveNesting[$class->name]); } } diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php index 98aea6e47..28a7e2664 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php @@ -223,21 +223,32 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertTrue($isFieldMapped); } - public function testThrowsExceptionOnInfiniteEmbeddableNesting() + /** + * @dataProvider getInfiniteEmbeddableNestingData + */ + public function testThrowsExceptionOnInfiniteEmbeddableNesting($embeddableClassName, $declaredEmbeddableClassName) { $this->setExpectedException( 'Doctrine\ORM\Mapping\MappingException', sprintf( 'Infinite nesting detected for embedded property %s::nested. ' . 'You cannot embed an embeddable from the same type inside an embeddable.', - __NAMESPACE__ . '\DDCInfiniteNestingEmbeddable' + __NAMESPACE__ . '\\' . $declaredEmbeddableClassName ) ); $this->_schemaTool->createSchema(array( - $this->_em->getClassMetadata(__NAMESPACE__ . '\DDCInfiniteNestingEmbeddable'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\' . $embeddableClassName), )); } + + public function getInfiniteEmbeddableNestingData() + { + return array( + array('DDCInfiniteNestingEmbeddable', 'DDCInfiniteNestingEmbeddable'), + array('DDCNestingEmbeddable1', 'DDCNestingEmbeddable4'), + ); + } } @@ -512,3 +523,63 @@ class DDCInfiniteNestingEmbeddable /** @Embedded(class="DDCInfiniteNestingEmbeddable") */ public $nested; } + +/** + * @Embeddable + */ +class DDCNestingEmbeddable1 +{ + /** @Embedded(class="DDC3028Id") */ + public $id1; + + /** @Embedded(class="DDC3028Id") */ + public $id2; + + /** @Embedded(class="DDCNestingEmbeddable2") */ + public $nested; +} + +/** + * @Embeddable + */ +class DDCNestingEmbeddable2 +{ + /** @Embedded(class="DDC3028Id") */ + public $id1; + + /** @Embedded(class="DDC3028Id") */ + public $id2; + + /** @Embedded(class="DDCNestingEmbeddable3") */ + public $nested; +} + +/** + * @Embeddable + */ +class DDCNestingEmbeddable3 +{ + /** @Embedded(class="DDC3028Id") */ + public $id1; + + /** @Embedded(class="DDC3028Id") */ + public $id2; + + /** @Embedded(class="DDCNestingEmbeddable4") */ + public $nested; +} + +/** + * @Embeddable + */ +class DDCNestingEmbeddable4 +{ + /** @Embedded(class="DDC3028Id") */ + public $id1; + + /** @Embedded(class="DDC3028Id") */ + public $id2; + + /** @Embedded(class="DDCNestingEmbeddable1") */ + public $nested; +}