Merge pull request #1105 from deeky666/nested-embeddables
Add support for nesting embeddables
This commit is contained in:
commit
400acad533
@ -64,6 +64,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
*/
|
||||
private $evm;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $embeddablesActiveNesting = array();
|
||||
|
||||
/**
|
||||
* @param EntityManager $em
|
||||
*/
|
||||
@ -142,15 +147,27 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
}
|
||||
|
||||
if (!$class->isMappedSuperclass) {
|
||||
|
||||
foreach ($class->embeddedClasses as $property => $embeddableClass) {
|
||||
|
||||
if (isset($embeddableClass['inherited'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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) {
|
||||
$this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property);
|
||||
}
|
||||
|
||||
$class->inlineEmbeddable($property, $embeddableMetadata);
|
||||
|
||||
unset($this->embeddablesActiveNesting[$class->name]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,6 +387,34 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds nested embedded classes metadata to a parent class.
|
||||
*
|
||||
* @param ClassMetadata $subClass Sub embedded class metadata to add nested embedded classes metadata from.
|
||||
* @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to.
|
||||
* @param string $prefix Embedded classes' prefix to use for nested embedded classes field names.
|
||||
*/
|
||||
private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix)
|
||||
{
|
||||
foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
|
||||
if (isset($embeddableClass['inherited'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$embeddableMetadata = $this->getMetadataFor($embeddableClass['class']);
|
||||
|
||||
$parentClass->mapEmbedded(array(
|
||||
'fieldName' => $prefix . '.' . $property,
|
||||
'class' => $embeddableMetadata->name,
|
||||
'columnPrefix' => $embeddableClass['columnPrefix'],
|
||||
'declaredField' => $embeddableClass['declaredField']
|
||||
? $prefix . '.' . $embeddableClass['declaredField']
|
||||
: $prefix,
|
||||
'originalField' => $embeddableClass['originalField'] ?: $property,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds inherited named queries to the subclass mapping.
|
||||
*
|
||||
|
@ -930,15 +930,31 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
// Restore ReflectionClass and properties
|
||||
$this->reflClass = $reflService->getClass($this->name);
|
||||
|
||||
$parentReflFields = array();
|
||||
|
||||
foreach ($this->embeddedClasses as $property => $embeddedClass) {
|
||||
if (isset($embeddedClass['declaredField'])) {
|
||||
$parentReflFields[$property] = new ReflectionEmbeddedProperty(
|
||||
$parentReflFields[$embeddedClass['declaredField']],
|
||||
$reflService->getAccessibleProperty(
|
||||
$this->embeddedClasses[$embeddedClass['declaredField']]['class'],
|
||||
$embeddedClass['originalField']
|
||||
),
|
||||
$embeddedClass['class']
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$parentReflFields[$property] = $reflService->getAccessibleProperty($this->name, $property);
|
||||
}
|
||||
|
||||
foreach ($this->fieldMappings as $field => $mapping) {
|
||||
if (isset($mapping['declaredField'])) {
|
||||
$declaringClass = isset($this->embeddedClasses[$mapping['declaredField']]['declared'])
|
||||
? $this->embeddedClasses[$mapping['declaredField']]['declared'] : $this->name;
|
||||
|
||||
$this->reflFields[$field] = new ReflectionEmbeddedProperty(
|
||||
$reflService->getAccessibleProperty($declaringClass, $mapping['declaredField']),
|
||||
$reflService->getAccessibleProperty($this->embeddedClasses[$mapping['declaredField']]['class'], $mapping['originalField']),
|
||||
$this->embeddedClasses[$mapping['declaredField']]['class']
|
||||
$parentReflFields[$mapping['declaredField']],
|
||||
$reflService->getAccessibleProperty($mapping['originalClass'], $mapping['originalField']),
|
||||
$mapping['originalClass']
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@ -3172,15 +3188,13 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function mapEmbedded(array $mapping)
|
||||
{
|
||||
if ($this->isEmbeddedClass) {
|
||||
throw MappingException::noEmbeddablesInEmbeddable($this->name);
|
||||
}
|
||||
|
||||
$this->assertFieldNotMapped($mapping['fieldName']);
|
||||
|
||||
$this->embeddedClasses[$mapping['fieldName']] = array(
|
||||
'class' => $this->fullyQualifiedClassName($mapping['class']),
|
||||
'columnPrefix' => $mapping['columnPrefix'],
|
||||
'declaredField' => isset($mapping['declaredField']) ? $mapping['declaredField'] : null,
|
||||
'originalField' => isset($mapping['originalField']) ? $mapping['originalField'] : null,
|
||||
);
|
||||
}
|
||||
|
||||
@ -3193,8 +3207,15 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
public function inlineEmbeddable($property, ClassMetadataInfo $embeddable)
|
||||
{
|
||||
foreach ($embeddable->fieldMappings as $fieldMapping) {
|
||||
$fieldMapping['declaredField'] = $property;
|
||||
$fieldMapping['originalField'] = $fieldMapping['fieldName'];
|
||||
$fieldMapping['originalClass'] = isset($fieldMapping['originalClass'])
|
||||
? $fieldMapping['originalClass']
|
||||
: $embeddable->name;
|
||||
$fieldMapping['declaredField'] = isset($fieldMapping['declaredField'])
|
||||
? $property . '.' . $fieldMapping['declaredField']
|
||||
: $property;
|
||||
$fieldMapping['originalField'] = isset($fieldMapping['originalField'])
|
||||
? $fieldMapping['originalField']
|
||||
: $fieldMapping['fieldName'];
|
||||
$fieldMapping['fieldName'] = $property . "." . $fieldMapping['fieldName'];
|
||||
|
||||
if (! empty($this->embeddedClasses[$property]['columnPrefix'])) {
|
||||
|
@ -782,11 +782,21 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
);
|
||||
}
|
||||
|
||||
public static function noEmbeddablesInEmbeddable($className)
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $propertyName
|
||||
*
|
||||
* @return MappingException
|
||||
*/
|
||||
public static function infiniteEmbeddableNesting($className, $propertyName)
|
||||
{
|
||||
return new self(sprintf(
|
||||
"You embedded one or more embeddables in embeddable '%s', but this behavior is currently unsupported.",
|
||||
$className
|
||||
));
|
||||
return new self(
|
||||
sprintf(
|
||||
'Infinite nesting detected for embedded property %s::%s. ' .
|
||||
'You cannot embed an embeddable from the same type inside an embeddable.',
|
||||
$className,
|
||||
$propertyName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$person->address->street = "United States of Tara Street";
|
||||
$person->address->zip = "12345";
|
||||
$person->address->city = "funkytown";
|
||||
$person->address->country = new DDC93Country('Germany');
|
||||
|
||||
// 1. check saving value objects works
|
||||
$this->_em->persist($person);
|
||||
@ -46,11 +47,14 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals('United States of Tara Street', $person->address->street);
|
||||
$this->assertEquals('12345', $person->address->zip);
|
||||
$this->assertEquals('funkytown', $person->address->city);
|
||||
$this->assertInstanceOf(DDC93Country::CLASSNAME, $person->address->country);
|
||||
$this->assertEquals('Germany', $person->address->country->name);
|
||||
|
||||
// 3. check changing value objects works
|
||||
$person->address->street = "Street";
|
||||
$person->address->zip = "54321";
|
||||
$person->address->city = "another town";
|
||||
$person->address->country->name = "United States of America";
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->clear();
|
||||
@ -60,6 +64,7 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals('Street', $person->address->street);
|
||||
$this->assertEquals('54321', $person->address->zip);
|
||||
$this->assertEquals('another town', $person->address->city);
|
||||
$this->assertEquals('United States of America', $person->address->country->name);
|
||||
|
||||
// 4. check deleting works
|
||||
$personId = $person->id;;
|
||||
@ -78,6 +83,7 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$person->address->street = "Tree";
|
||||
$person->address->zip = "12345";
|
||||
$person->address->city = "funkytown";
|
||||
$person->address->country = new DDC93Country('United States of America');
|
||||
|
||||
$this->_em->persist($person);
|
||||
}
|
||||
@ -94,6 +100,8 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals('Tree', $person->address->street);
|
||||
$this->assertEquals('12345', $person->address->zip);
|
||||
$this->assertEquals('funkytown', $person->address->city);
|
||||
$this->assertInstanceOf(DDC93Country::CLASSNAME, $person->address->country);
|
||||
$this->assertEquals('United States of America', $person->address->country->name);
|
||||
}
|
||||
|
||||
$dql = "SELECT p FROM " . __NAMESPACE__ . "\DDC93Person p";
|
||||
@ -103,6 +111,7 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals('Tree', $person['address.street']);
|
||||
$this->assertEquals('12345', $person['address.zip']);
|
||||
$this->assertEquals('funkytown', $person['address.city']);
|
||||
$this->assertEquals('United States of America', $person['address.country.name']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,32 +124,41 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->markTestSkipped('SLC does not work with UPDATE/DELETE queries through EM.');
|
||||
}
|
||||
|
||||
$person = new DDC93Person('Johannes', new DDC93Address('Moo', '12345', 'Karlsruhe'));
|
||||
$person = new DDC93Person('Johannes', new DDC93Address('Moo', '12345', 'Karlsruhe', new DDC93Country('Germany')));
|
||||
$this->_em->persist($person);
|
||||
$this->_em->flush($person);
|
||||
|
||||
// SELECT
|
||||
$selectDql = "SELECT p FROM " . __NAMESPACE__ ."\\DDC93Person p WHERE p.address.city = :city";
|
||||
$selectDql = "SELECT p FROM " . __NAMESPACE__ ."\\DDC93Person p WHERE p.address.city = :city AND p.address.country.name = :country";
|
||||
$loadedPerson = $this->_em->createQuery($selectDql)
|
||||
->setParameter('city', 'Karlsruhe')
|
||||
->setParameter('country', 'Germany')
|
||||
->getSingleResult();
|
||||
$this->assertEquals($person, $loadedPerson);
|
||||
|
||||
$this->assertNull($this->_em->createQuery($selectDql)->setParameter('city', 'asdf')->getOneOrNullResult());
|
||||
$this->assertNull(
|
||||
$this->_em->createQuery($selectDql)
|
||||
->setParameter('city', 'asdf')
|
||||
->setParameter('country', 'Germany')
|
||||
->getOneOrNullResult()
|
||||
);
|
||||
|
||||
// UPDATE
|
||||
$updateDql = "UPDATE " . __NAMESPACE__ . "\\DDC93Person p SET p.address.street = :street WHERE p.address.city = :city";
|
||||
$updateDql = "UPDATE " . __NAMESPACE__ . "\\DDC93Person p SET p.address.street = :street, p.address.country.name = :country WHERE p.address.city = :city";
|
||||
$this->_em->createQuery($updateDql)
|
||||
->setParameter('street', 'Boo')
|
||||
->setParameter('country', 'DE')
|
||||
->setParameter('city', 'Karlsruhe')
|
||||
->execute();
|
||||
|
||||
$this->_em->refresh($person);
|
||||
$this->assertEquals('Boo', $person->address->street);
|
||||
$this->assertEquals('DE', $person->address->country->name);
|
||||
|
||||
// DELETE
|
||||
$this->_em->createQuery("DELETE " . __NAMESPACE__ . "\\DDC93Person p WHERE p.address.city = :city")
|
||||
$this->_em->createQuery("DELETE " . __NAMESPACE__ . "\\DDC93Person p WHERE p.address.city = :city AND p.address.country.name = :country")
|
||||
->setParameter('city', 'Karlsruhe')
|
||||
->setParameter('country', 'DE')
|
||||
->execute();
|
||||
|
||||
$this->_em->clear();
|
||||
@ -165,43 +183,24 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals($car, $reloadedCar);
|
||||
}
|
||||
|
||||
public function testEmbeddableWithinEmbeddable()
|
||||
{
|
||||
$this->setExpectedException(
|
||||
'Doctrine\ORM\Mapping\MappingException',
|
||||
sprintf(
|
||||
"You embedded one or more embeddables in embeddable '%s', but this behavior is currently unsupported.",
|
||||
__NAMESPACE__ . '\DDC93ContactInfo'
|
||||
)
|
||||
);
|
||||
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93Customer'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93ContactInfo'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93PhoneNumber')
|
||||
));
|
||||
}
|
||||
|
||||
public function testInlineEmbeddableWithPrefix()
|
||||
{
|
||||
$expectedColumnName = 'foobar_id';
|
||||
$metadata = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC3028PersonWithPrefix');
|
||||
|
||||
$actualColumnName = $this->_em
|
||||
->getClassMetadata(__NAMESPACE__ . '\DDC3028PersonWithPrefix')
|
||||
->getColumnName('id.id');
|
||||
|
||||
$this->assertEquals($expectedColumnName, $actualColumnName);
|
||||
$this->assertEquals('foobar_id', $metadata->getColumnName('id.id'));
|
||||
$this->assertEquals('bloo_foo_id', $metadata->getColumnName('nested.nestedWithPrefix.id'));
|
||||
$this->assertEquals('bloo_nestedWithEmptyPrefix_id', $metadata->getColumnName('nested.nestedWithEmptyPrefix.id'));
|
||||
$this->assertEquals('bloo_id', $metadata->getColumnName('nested.nestedWithPrefixFalse.id'));
|
||||
}
|
||||
|
||||
public function testInlineEmbeddableEmptyPrefix()
|
||||
{
|
||||
$expectedColumnName = 'id_id';
|
||||
$metadata = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC3028PersonEmptyPrefix');
|
||||
|
||||
$actualColumnName = $this->_em
|
||||
->getClassMetadata(__NAMESPACE__ . '\DDC3028PersonEmptyPrefix')
|
||||
->getColumnName('id.id');
|
||||
|
||||
$this->assertEquals($expectedColumnName, $actualColumnName);
|
||||
$this->assertEquals('id_id', $metadata->getColumnName('id.id'));
|
||||
$this->assertEquals('nested_foo_id', $metadata->getColumnName('nested.nestedWithPrefix.id'));
|
||||
$this->assertEquals('nested_nestedWithEmptyPrefix_id', $metadata->getColumnName('nested.nestedWithEmptyPrefix.id'));
|
||||
$this->assertEquals('nested_id', $metadata->getColumnName('nested.nestedWithPrefixFalse.id'));
|
||||
}
|
||||
|
||||
public function testInlineEmbeddablePrefixFalse()
|
||||
@ -223,6 +222,33 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->assertTrue($isFieldMapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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__ . '\\' . $declaredEmbeddableClassName
|
||||
)
|
||||
);
|
||||
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\' . $embeddableClassName),
|
||||
));
|
||||
}
|
||||
|
||||
public function getInfiniteEmbeddableNestingData()
|
||||
{
|
||||
return array(
|
||||
array('DDCInfiniteNestingEmbeddable', 'DDCInfiniteNestingEmbeddable'),
|
||||
array('DDCNestingEmbeddable1', 'DDCNestingEmbeddable4'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -297,6 +323,24 @@ class DDC93Car extends DDC93Vehicle
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @Embeddable
|
||||
*/
|
||||
class DDC93Country
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
/**
|
||||
* @Column(type="string", nullable=true)
|
||||
*/
|
||||
public $name;
|
||||
|
||||
public function __construct($name = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Embeddable
|
||||
*/
|
||||
@ -316,12 +360,15 @@ class DDC93Address
|
||||
* @Column(type="string")
|
||||
*/
|
||||
public $city;
|
||||
/** @Embedded(class = "DDC93Country") */
|
||||
public $country;
|
||||
|
||||
public function __construct($street = null, $zip = null, $city = null)
|
||||
public function __construct($street = null, $zip = null, $city = null, DDC93Country $country = null)
|
||||
{
|
||||
$this->street = $street;
|
||||
$this->zip = $zip;
|
||||
$this->city = $city;
|
||||
$this->country = $country;
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,8 +385,14 @@ class DDC93Customer
|
||||
/** @Embeddable */
|
||||
class DDC93ContactInfo
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
/**
|
||||
* @Column(type="string")
|
||||
*/
|
||||
public $email;
|
||||
/** @Embedded(class = "DDC93Address") */
|
||||
private $address;
|
||||
public $address;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -352,9 +405,13 @@ class DDC3028PersonWithPrefix
|
||||
/** @Embedded(class="DDC3028Id", columnPrefix = "foobar_") */
|
||||
public $id;
|
||||
|
||||
public function __construct(DDC3028Id $id = null)
|
||||
/** @Embedded(class="DDC3028NestedEmbeddable", columnPrefix = "bloo_") */
|
||||
public $nested;
|
||||
|
||||
public function __construct(DDC3028Id $id = null, DDC3028NestedEmbeddable $nested = null)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->nested = $nested;
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,9 +425,13 @@ class DDC3028PersonEmptyPrefix
|
||||
/** @Embedded(class="DDC3028Id", columnPrefix = "") */
|
||||
public $id;
|
||||
|
||||
public function __construct(DDC3028Id $id = null)
|
||||
/** @Embedded(class="DDC3028NestedEmbeddable", columnPrefix = "") */
|
||||
public $nested;
|
||||
|
||||
public function __construct(DDC3028Id $id = null, DDC3028NestedEmbeddable $nested = null)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->nested = $nested;
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,6 +469,33 @@ class DDC3028Id
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Embeddable
|
||||
*/
|
||||
class DDC3028NestedEmbeddable
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
/** @Embedded(class="DDC3028Id", columnPrefix = "foo_") */
|
||||
public $nestedWithPrefix;
|
||||
|
||||
/** @Embedded(class="DDC3028Id", columnPrefix = "") */
|
||||
public $nestedWithEmptyPrefix;
|
||||
|
||||
/** @Embedded(class="DDC3028Id", columnPrefix = false) */
|
||||
public $nestedWithPrefixFalse;
|
||||
|
||||
public function __construct(
|
||||
DDC3028Id $nestedWithPrefix = null,
|
||||
DDC3028Id $nestedWithEmptyPrefix = null,
|
||||
DDC3028Id $nestedWithPrefixFalse = null
|
||||
) {
|
||||
$this->nestedWithPrefix = $nestedWithPrefix;
|
||||
$this->nestedWithEmptyPrefix = $nestedWithEmptyPrefix;
|
||||
$this->nestedWithPrefixFalse = $nestedWithPrefixFalse;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @MappedSuperclass
|
||||
*/
|
||||
@ -426,3 +514,72 @@ abstract class DDC3027Animal
|
||||
class DDC3027Dog extends DDC3027Animal
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @Embeddable
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -65,7 +65,9 @@ class XmlMappingDriverTest extends AbstractMappingDriverTest
|
||||
array(
|
||||
'name' => array(
|
||||
'class' => 'Doctrine\Tests\Models\ValueObjects\Name',
|
||||
'columnPrefix' => 'nm_'
|
||||
'columnPrefix' => 'nm_',
|
||||
'declaredField' => null,
|
||||
'originalField' => null,
|
||||
)
|
||||
),
|
||||
$class->embeddedClasses
|
||||
|
Loading…
x
Reference in New Issue
Block a user