diff --git a/doctrine-mongo-mapping.xsd b/doctrine-mongo-mapping.xsd index db193485b8..57a60acd86 100644 --- a/doctrine-mongo-mapping.xsd +++ b/doctrine-mongo-mapping.xsd @@ -109,10 +109,10 @@ + - @@ -154,6 +154,7 @@ + @@ -165,7 +166,6 @@ - diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php index f40879852d..85653d2f96 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php @@ -2058,6 +2058,24 @@ public function getAssociationTargetClass($assocName) return $this->associationMappings[$assocName]['targetDocument']; } + /** + * Retrieve the collectionClass associated with an association + * + * @param string $assocName + */ + public function getAssociationCollectionClass($assocName) + { + if ( ! isset($this->associationMappings[$assocName])) { + throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association."); + } + + if ( ! array_key_exists('collectionClass', $this->associationMappings[$assocName])) { + throw new InvalidArgumentException("collectionClass can only be applied to 'embedMany' and 'referenceMany' associations."); + } + + return $this->associationMappings[$assocName]['collectionClass']; + } + /** * {@inheritDoc} */ diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php index 14ab346b72..82e4408a33 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php @@ -244,11 +244,12 @@ private function addEmbedMapping(ClassMetadataInfo $class, $embed, $type) $attributes = $embed->attributes(); $defaultStrategy = $type == 'one' ? ClassMetadataInfo::STORAGE_STRATEGY_SET : CollectionHelper::DEFAULT_STRATEGY; $mapping = array( - 'type' => $type, - 'embedded' => true, - 'targetDocument' => isset($attributes['target-document']) ? (string) $attributes['target-document'] : null, - 'name' => (string) $attributes['field'], - 'strategy' => isset($attributes['strategy']) ? (string) $attributes['strategy'] : $defaultStrategy, + 'type' => $type, + 'embedded' => true, + 'targetDocument' => isset($attributes['target-document']) ? (string) $attributes['target-document'] : null, + 'collectionClass' => isset($attributes['collection-class']) ? (string) $attributes['collection-class'] : null, + 'name' => (string) $attributes['field'], + 'strategy' => isset($attributes['strategy']) ? (string) $attributes['strategy'] : $defaultStrategy, ); if (isset($attributes['fieldName'])) { $mapping['fieldName'] = (string) $attributes['fieldName']; @@ -291,6 +292,7 @@ private function addReferenceMapping(ClassMetadataInfo $class, $reference, $type 'simple' => isset($attributes['simple']) ? ('true' === (string) $attributes['simple']) : false, // deprecated 'storeAs' => isset($attributes['store-as']) ? (string) $attributes['store-as'] : ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, 'targetDocument' => isset($attributes['target-document']) ? (string) $attributes['target-document'] : null, + 'collectionClass' => isset($attributes['collection-class']) ? (string) $attributes['collection-class'] : null, 'name' => (string) $attributes['field'], 'strategy' => isset($attributes['strategy']) ? (string) $attributes['strategy'] : $defaultStrategy, 'inversedBy' => isset($attributes['inversed-by']) ? (string) $attributes['inversed-by'] : null, diff --git a/lib/Doctrine/ODM/MongoDB/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ODM/MongoDB/Mapping/Driver/YamlDriver.php index 77cf4d375c..95fd1fdaab 100644 --- a/lib/Doctrine/ODM/MongoDB/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ODM/MongoDB/Mapping/Driver/YamlDriver.php @@ -242,11 +242,12 @@ private function addMappingFromEmbed(ClassMetadataInfo $class, $fieldName, $embe { $defaultStrategy = $type == 'one' ? ClassMetadataInfo::STORAGE_STRATEGY_SET : CollectionHelper::DEFAULT_STRATEGY; $mapping = array( - 'type' => $type, - 'embedded' => true, - 'targetDocument' => isset($embed['targetDocument']) ? $embed['targetDocument'] : null, - 'fieldName' => $fieldName, - 'strategy' => isset($embed['strategy']) ? (string) $embed['strategy'] : $defaultStrategy, + 'type' => $type, + 'embedded' => true, + 'targetDocument' => isset($embed['targetDocument']) ? $embed['targetDocument'] : null, + 'collectionClass' => isset($embed['collectionClass']) ? $embed['collectionClass'] : null, + 'fieldName' => $fieldName, + 'strategy' => isset($embed['strategy']) ? (string) $embed['strategy'] : $defaultStrategy, ); if (isset($embed['name'])) { $mapping['name'] = $embed['name']; @@ -274,6 +275,7 @@ private function addMappingFromReference(ClassMetadataInfo $class, $fieldName, $ 'simple' => isset($reference['simple']) ? (boolean) $reference['simple'] : false, // deprecated 'storeAs' => isset($reference['storeAs']) ? (string) $reference['storeAs'] : ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, 'targetDocument' => isset($reference['targetDocument']) ? $reference['targetDocument'] : null, + 'collectionClass' => isset($reference['collectionClass']) ? $reference['collectionClass'] : null, 'fieldName' => $fieldName, 'strategy' => isset($reference['strategy']) ? (string) $reference['strategy'] : $defaultStrategy, 'inversedBy' => isset($reference['inversedBy']) ? (string) $reference['inversedBy'] : null, diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/AbstractMappingDriverTest.php index 5a81b391d0..1e04fa144c 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/AbstractMappingDriverTest.php @@ -405,7 +405,7 @@ class AbstractMappingDriverUser public $address; /** - * @ODM\ReferenceMany(targetDocument="Phonenumber", cascade={"persist"}, discriminatorField="discr", discriminatorMap={"home"="HomePhonenumber", "work"="WorkPhonenumber"}, defaultDiscriminatorValue="home") + * @ODM\ReferenceMany(targetDocument="Phonenumber", collectionClass="PhonenumberCollection", cascade={"persist"}, discriminatorField="discr", discriminatorMap={"home"="HomePhonenumber", "work"="WorkPhonenumber"}, defaultDiscriminatorValue="home") */ public $phonenumbers; @@ -415,7 +415,7 @@ class AbstractMappingDriverUser public $groups; /** - * @ODM\ReferenceMany(targetDocument="Phonenumber", name="more_phone_numbers") + * @ODM\ReferenceMany(targetDocument="Phonenumber", collectionClass="PhonenumberCollection", name="more_phone_numbers") */ public $morePhoneNumbers; @@ -509,6 +509,7 @@ public static function loadMetadata(ClassMetadata $metadata) $metadata->mapManyReference(array( 'fieldName' => 'phonenumbers', 'targetDocument' => 'Doctrine\\ODM\\MongoDB\\Tests\\Mapping\\Phonenumber', + 'collectionClass' => 'Doctrine\\ODM\\MongoDB\\Tests\\Mapping\\PhonenumberCollection', 'cascade' => array(1 => 'persist'), 'discriminatorField' => 'discr', 'discriminatorMap' => array( @@ -521,6 +522,7 @@ public static function loadMetadata(ClassMetadata $metadata) 'fieldName' => 'morePhoneNumbers', 'name' => 'more_phone_numbers', 'targetDocument' => 'Doctrine\\ODM\\MongoDB\\Tests\\Mapping\\Phonenumber', + 'collectionClass' => 'Doctrine\\ODM\\MongoDB\\Tests\\Mapping\\PhonenumberCollection', )); $metadata->mapManyReference(array( 'fieldName' => 'groups', diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/AbstractDriverTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/AbstractDriverTest.php index 63305c7e8e..1bc1095d65 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/AbstractDriverTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/Driver/AbstractDriverTest.php @@ -106,6 +106,7 @@ public function testDriver() 'type' => 'one', 'embedded' => true, 'targetDocument' => 'Documents\Address', + 'collectionClass' => null, 'isCascadeDetach' => true, 'isCascadeMerge' => true, 'isCascadePersist' => true, @@ -124,6 +125,7 @@ public function testDriver() 'type' => 'many', 'embedded' => true, 'targetDocument' => 'Documents\Phonenumber', + 'collectionClass' => null, 'isCascadeDetach' => true, 'isCascadeMerge' => true, 'isCascadePersist' => true, @@ -144,6 +146,7 @@ public function testDriver() 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_ID, 'simple' => true, 'targetDocument' => 'Documents\Profile', + 'collectionClass' => null, 'cascade' => array('remove', 'persist', 'refresh', 'merge', 'detach'), 'isCascadeDetach' => true, 'isCascadeMerge' => true, @@ -171,6 +174,7 @@ public function testDriver() 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, 'simple' => false, 'targetDocument' => 'Documents\Account', + 'collectionClass' => null, 'cascade' => array('remove', 'persist', 'refresh', 'merge', 'detach'), 'isCascadeDetach' => true, 'isCascadeMerge' => true, @@ -198,6 +202,7 @@ public function testDriver() 'storeAs' => ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB, 'simple' => false, 'targetDocument' => 'Documents\Group', + 'collectionClass' => null, 'cascade' => array('remove', 'persist', 'refresh', 'merge', 'detach'), 'isCascadeDetach' => true, 'isCascadeMerge' => true, diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/XmlMappingDriverTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/XmlMappingDriverTest.php index 89865d2b4c..ace15b9cd1 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/XmlMappingDriverTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/XmlMappingDriverTest.php @@ -28,4 +28,18 @@ public function testSetShardKeyOptionsByAttributes() $this->assertSame(array('unique' => true, 'numInitialChunks' => 4096), $shardKey['options']); $this->assertSame(array('_id' => 1), $shardKey['keys']); } -} \ No newline at end of file + + public function testGetAssociationCollectionClass() + { + $class = new ClassMetadataInfo('doc'); + $driver = $this->_loadDriver(); + $element = new \SimpleXmlElement(''); + + /** @uses XmlDriver::setShardKey */ + $m = new \ReflectionMethod(get_class($driver), 'addReferenceMapping'); + $m->setAccessible(true); + $m->invoke($driver, $class, $element, 'many'); + + $this->assertEquals('Doctrine\\ODM\\MongoDB\\Tests\\Mapping\\PhonenumberCollection', $class->getAssociationCollectionClass('phonenumbers')); + } +} diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/YamlMappingDriverTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/YamlMappingDriverTest.php index c351682e25..ab5e998034 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/YamlMappingDriverTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/YamlMappingDriverTest.php @@ -31,12 +31,23 @@ public function testAlternateRelationshipMappingSyntaxShouldSetDefaults() } foreach (array('embeddedPhonenumber', 'otherPhonenumbers') as $embeddedField) { - foreach (array('strategy', 'targetDocument') as $key) { + foreach (array('strategy', 'targetDocument', 'collectionClass') as $key) { $this->assertArrayHasKey($key, $class->fieldMappings[$embeddedField]); } } } + public function testGetAssociationCollectionClass() + { + $className = __NAMESPACE__.'\AbstractMappingDriverUser'; + $mappingDriver = new YamlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'yaml'); + + $class = new ClassMetadata($className); + $mappingDriver->loadMetadataForClass($className, $class); + $this->assertEquals('Doctrine\ODM\MongoDB\Tests\Mapping\PhonenumberCollection', $class->getAssociationCollectionClass('phonenumbers')); + $this->assertEquals('Doctrine\ODM\MongoDB\Tests\Mapping\PhonenumberCollection', $class->getAssociationCollectionClass('otherPhonenumbers')); + } + public function testFieldLevelIndexSyntaxWithBooleanValues() { $className = __NAMESPACE__.'\AbstractMappingDriverAlternateUser'; @@ -70,3 +81,8 @@ class AbstractMappingDriverAlternateUser public $embeddedPhonenumber; public $otherPhonenumbers; } + +class PhonenumberCollection extends \Doctrine\Common\Collections\ArrayCollection +{ + +} diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/xml/Doctrine.ODM.MongoDB.Tests.Mapping.AbstractMappingDriverUser.dcm.xml b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/xml/Doctrine.ODM.MongoDB.Tests.Mapping.AbstractMappingDriverUser.dcm.xml index 679414acab..e3676e991c 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/xml/Doctrine.ODM.MongoDB.Tests.Mapping.AbstractMappingDriverUser.dcm.xml +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/xml/Doctrine.ODM.MongoDB.Tests.Mapping.AbstractMappingDriverUser.dcm.xml @@ -41,7 +41,7 @@ - + @@ -61,7 +61,7 @@ - + diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/yaml/Doctrine.ODM.MongoDB.Tests.Mapping.AbstractMappingDriverUser.dcm.yml b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/yaml/Doctrine.ODM.MongoDB.Tests.Mapping.AbstractMappingDriverUser.dcm.yml index f0a0b80a4b..6df9f3211a 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Mapping/yaml/Doctrine.ODM.MongoDB.Tests.Mapping.AbstractMappingDriverUser.dcm.yml +++ b/tests/Doctrine/ODM/MongoDB/Tests/Mapping/yaml/Doctrine.ODM.MongoDB.Tests.Mapping.AbstractMappingDriverUser.dcm.yml @@ -67,6 +67,7 @@ Doctrine\ODM\MongoDB\Tests\Mapping\AbstractMappingDriverUser: referenceMany: phonenumbers: targetDocument: Phonenumber + collectionClass: PhonenumberCollection cascade: [ persist ] discriminatorField: discr discriminatorMap: @@ -86,6 +87,7 @@ Doctrine\ODM\MongoDB\Tests\Mapping\AbstractMappingDriverUser: embedMany: otherPhonenumbers: targetDocument: Phonenumber + collectionClass: PhonenumberCollection discriminatorField: discr discriminatorMap: home: HomePhonenumber