diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 40f50962a..9e895fcbc 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -454,6 +454,7 @@ Things to note: - This feature is available for all kind of associations. (OneToOne, OneToMany, ManyToOne, ManyToMany) - The association type *CANNOT* be changed. - The override could redefine the joinTables or joinColumns depending on the association type. +- The override could redefine inversedBy to reference more than one extended entity. Attribute Override ~~~~~~~~~~~~~~~~~~~~ diff --git a/doctrine-mapping.xsd b/doctrine-mapping.xsd index 6a7e2a284..aef47b2a6 100644 --- a/doctrine-mapping.xsd +++ b/doctrine-mapping.xsd @@ -563,11 +563,16 @@ + + + + + diff --git a/lib/Doctrine/ORM/Mapping/AssociationOverride.php b/lib/Doctrine/ORM/Mapping/AssociationOverride.php index 1a9a31f18..83cff4179 100644 --- a/lib/Doctrine/ORM/Mapping/AssociationOverride.php +++ b/lib/Doctrine/ORM/Mapping/AssociationOverride.php @@ -50,4 +50,11 @@ final class AssociationOverride implements Annotation * @var \Doctrine\ORM\Mapping\JoinTable */ public $joinTable; + + /** + * The name of the association-field on the inverse-side. + * + * @var string + */ + public $inversedBy; } diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index f53999ce8..73f7dc647 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -2126,6 +2126,10 @@ class ClassMetadataInfo implements ClassMetadata $mapping['joinColumns'] = $overrideMapping['joinColumns']; } + if (isset($overrideMapping['inversedBy'])) { + $mapping['inversedBy'] = $overrideMapping['inversedBy']; + } + if (isset($overrideMapping['joinTable'])) { $mapping['joinTable'] = $overrideMapping['joinTable']; } diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index e8af86e84..a4e88dc51 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -440,6 +440,11 @@ class AnnotationDriver extends AbstractAnnotationDriver $override['joinTable'] = $joinTable; } + // Check for inversedBy + if ($associationOverride->inversedBy) { + $override['inversedBy'] = $associationOverride->inversedBy; + } + $metadata->setAssociationOverride($fieldName, $override); } } diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index 7f9a7ecc9..0dfbb850e 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -605,6 +605,11 @@ class XmlDriver extends FileDriver $override['joinTable'] = $joinTable; } + // Check for inversed-by + if (isset($overrideElement->{'inversed-by'})) { + $override['inversedBy'] = (string) $overrideElement->{'inversed-by'}['name']; + } + $metadata->setAssociationOverride($fieldName, $override); } } diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index aa288d0cd..73fda462d 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -611,6 +611,11 @@ class YamlDriver extends FileDriver $override['joinTable'] = $joinTable; } + // Check for inversedBy + if (isset($associationOverrideElement['inversedBy'])) { + $override['inversedBy'] = (string) $associationOverrideElement['inversedBy']; + } + $metadata->setAssociationOverride($fieldName, $override); } } diff --git a/tests/Doctrine/Tests/Models/DDC3579/DDC3579Admin.php b/tests/Doctrine/Tests/Models/DDC3579/DDC3579Admin.php new file mode 100644 index 000000000..cc9803d44 --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC3579/DDC3579Admin.php @@ -0,0 +1,24 @@ +setAssociationOverride('groups', array( + 'inversedBy' => 'admins' + )); + } +} diff --git a/tests/Doctrine/Tests/Models/DDC3579/DDC3579Group.php b/tests/Doctrine/Tests/Models/DDC3579/DDC3579Group.php new file mode 100644 index 000000000..821c06b57 --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC3579/DDC3579Group.php @@ -0,0 +1,70 @@ +name = $name; + $this->users = new ArrayCollection(); + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param DDC3579Admin $admin + */ + public function addAdmin(DDC3579Admin $admin) + { + $this->admins[] = $admin; + } + + /** + * @return ArrayCollection + */ + public function getAdmins() + { + return $this->admins; + } + +} + diff --git a/tests/Doctrine/Tests/Models/DDC3579/DDC3579User.php b/tests/Doctrine/Tests/Models/DDC3579/DDC3579User.php new file mode 100644 index 000000000..7a7ea5de6 --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC3579/DDC3579User.php @@ -0,0 +1,108 @@ +name = $name; + $this->groups = new ArrayCollection; + } + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @param DDC3579Group $group + */ + public function addGroup(DDC3579Group $group) + { + $this->groups->add($group); + $group->addUser($this); + } + + /** + * @return ArrayCollection + */ + public function getGroups() + { + return $this->groups; + } + + public static function loadMetadata($metadata) + { + $metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'user_id', + 'length' => 150, + )); + + $metadata->mapField(array( + 'fieldName' => 'name', + 'type' => 'string', + 'columnName'=> 'user_name', + 'nullable' => true, + 'unique' => false, + 'length' => 250, + )); + + $metadata->mapManyToMany(array( + 'fieldName' => 'groups', + 'targetEntity' => 'DDC3579Group' + )); + + $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_AUTO); + } +} diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 248903c01..19d148b98 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -664,7 +664,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase $this->assertEquals($personMetadata->name, $mapping['entities'][0]['entityClass']); } - /* + /* * @group DDC-964 */ public function testAssociationOverridesMapping() @@ -747,6 +747,23 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase $this->assertEquals(array('id'=>'adminaddress_id'), $adminAddress['targetToSourceKeyColumns']); } + /* + * @group DDC-3579 + */ + public function testInversedByOverrideMapping() + { + + $factory = $this->createClassMetadataFactory(); + $adminMetadata = $factory->getMetadataFor('Doctrine\Tests\Models\DDC3579\DDC3579Admin'); + + // assert groups association mappings + $this->assertArrayHasKey('groups', $adminMetadata->associationMappings); + $adminGroups = $adminMetadata->associationMappings['groups']; + + // assert override + $this->assertEquals('admins', $adminGroups['inversedBy']); + } + /** * @group DDC-964 */ @@ -1339,4 +1356,4 @@ class Comment 'columnName' => 'content', )); } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC3579.DDC3579Admin.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC3579.DDC3579Admin.php new file mode 100644 index 000000000..dd59e65fa --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC3579.DDC3579Admin.php @@ -0,0 +1,5 @@ +setAssociationOverride('groups', array( + 'inversedBy' => 'admins' +)); diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC3579.DDC3579User.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC3579.DDC3579User.php new file mode 100644 index 000000000..1eb3555ec --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC3579.DDC3579User.php @@ -0,0 +1,27 @@ +mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'user_id', + 'length' => 150, +)); + +$metadata->mapField(array( + 'fieldName' => 'name', + 'type' => 'string', + 'columnName'=> 'user_name', + 'nullable' => true, + 'unique' => false, + 'length' => 250, +)); + +$metadata->mapManyToMany(array( + 'fieldName' => 'groups', + 'targetEntity' => 'DDC3579Group' +)); + +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.xml new file mode 100644 index 000000000..1f9286706 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.xml new file mode 100644 index 000000000..3b6e213f1 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.yml new file mode 100644 index 000000000..7420b14e6 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.yml @@ -0,0 +1,5 @@ +Doctrine\Tests\Models\DDC3579\DDC3579Admin: + type: entity + associationOverride: + groups: + inversedBy: admins diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.yml new file mode 100644 index 000000000..63d095035 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.yml @@ -0,0 +1,19 @@ +Doctrine\Tests\Models\DDC3579\DDC3579User: + type: mappedSuperclass + id: + id: + type: integer + column: user_id + length: 150 + generator: + strategy: AUTO + fields: + name: + type: string + column: user_name + length: 250 + nullable: true + unique: false + manyToMany: + groups: + targetEntity: DDC3579Group