diff --git a/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php index 448ad9904..8ebf68a16 100644 --- a/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php @@ -534,24 +534,28 @@ class ManyToManyPersister extends AbstractCollectionPersister $indexBy = $mapping['indexBy']; $id = $this->uow->getEntityIdentifier($collection->getOwner()); - $targetEntity = $this->em->getClassMetadata($mapping['targetEntity']); + $sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']); + $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); - if (! $mapping['isOwningSide']) { + if ( ! $mapping['isOwningSide']) { $associationSourceClass = $this->em->getClassMetadata($mapping['targetEntity']); - $mapping = $associationSourceClass->associationMappings[$mapping['mappedBy']]; + $mapping = $associationSourceClass->associationMappings[$mapping['mappedBy']]; $joinColumns = $mapping['joinTable']['joinColumns']; - $relationMode = 'relationToTargetKeyColumns'; + $sourceRelationMode = 'relationToTargetKeyColumns'; + $targetRelationMode = 'relationToSourceKeyColumns'; } else { - $joinColumns = $mapping['joinTable']['inverseJoinColumns']; $associationSourceClass = $this->em->getClassMetadata($mapping['sourceEntity']); - $relationMode = 'relationToSourceKeyColumns'; + $joinColumns = $mapping['joinTable']['inverseJoinColumns']; + $sourceRelationMode = 'relationToSourceKeyColumns'; + $targetRelationMode = 'relationToTargetKeyColumns'; } - $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $associationSourceClass, $this->platform). ' t'; + $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $associationSourceClass, $this->platform) . ' t'; $whereClauses = array(); $params = array(); + $types = array(); - $joinNeeded = !in_array($indexBy, $targetEntity->identifier); + $joinNeeded = ! in_array($indexBy, $targetClass->identifier); if ($joinNeeded) { // extra join needed if indexBy is not a @id $joinConditions = array(); @@ -559,21 +563,25 @@ class ManyToManyPersister extends AbstractCollectionPersister foreach ($joinColumns as $joinTableColumn) { $joinConditions[] = 't.' . $joinTableColumn['name'] . ' = tr.' . $joinTableColumn['referencedColumnName']; } - $tableName = $this->quoteStrategy->getTableName($targetEntity, $this->platform); + $tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform); $quotedJoinTable .= ' JOIN ' . $tableName . ' tr ON ' . implode(' AND ', $joinConditions); + $columnName = $targetClass->getColumnName($indexBy); - $whereClauses[] = 'tr.' . $targetEntity->getColumnName($indexBy) . ' = ?'; + $whereClauses[] = 'tr.' . $columnName . ' = ?'; $params[] = $key; - + $types[] = Helper::getTypeOfColumn($columnName, $targetClass, $this->em); } foreach ($mapping['joinTableColumns'] as $joinTableColumn) { - if (isset($mapping[$relationMode][$joinTableColumn])) { + if (isset($mapping[$sourceRelationMode][$joinTableColumn])) { + $column = $mapping[$sourceRelationMode][$joinTableColumn]; + $whereClauses[] = 't.' . $joinTableColumn . ' = ?'; $params[] = $id[$targetEntity->getFieldForColumn($mapping[$relationMode][$joinTableColumn])]; } elseif (!$joinNeeded) { $whereClauses[] = 't.' . $joinTableColumn . ' = ?'; $params[] = $key; + $types[] = Helper::getTypeOfColumn($column, $targetClass, $this->em); } } @@ -586,7 +594,7 @@ class ManyToManyPersister extends AbstractCollectionPersister } } - return array($quotedJoinTable, $whereClauses, $params); + return array($quotedJoinTable, $whereClauses, $params, $types); } /** @@ -618,6 +626,7 @@ class ManyToManyPersister extends AbstractCollectionPersister $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $sourceClass, $this->platform); $whereClauses = array(); $params = array(); + $types = array(); foreach ($mapping['joinTableColumns'] as $joinTableColumn) { $whereClauses[] = ($addFilters ? 't.' : '') . $joinTableColumn . ' = ?'; @@ -625,6 +634,11 @@ class ManyToManyPersister extends AbstractCollectionPersister if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) { $params[] = $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]; + $params[] = $targetClass->containsForeignIdentifier + ? $targetId[$targetClass->getFieldForColumn($column)] + : $targetId[$targetClass->fieldNames[$column]]; + $types[] = Helper::getTypeOfColumn($column, $targetClass, $this->em); + continue; } diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyExtraLazyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyExtraLazyEntity.php new file mode 100644 index 000000000..b139fa407 --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyExtraLazyEntity.php @@ -0,0 +1,33 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyExtraLazyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyExtraLazyEntity.php new file mode 100644 index 000000000..dda25b27d --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyExtraLazyEntity.php @@ -0,0 +1,38 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyExtraLazyTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyExtraLazyTest.php new file mode 100644 index 000000000..5d9a4dc41 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyExtraLazyTest.php @@ -0,0 +1,160 @@ +useModelSet('vct_manytomany_extralazy'); + parent::setUp(); + + $inversed1 = new Entity\InversedManyToManyExtraLazyEntity(); + $inversed1->id1 = 'abc'; + + $inversed2 = new Entity\InversedManyToManyExtraLazyEntity(); + $inversed2->id1 = 'def'; + + $owning1 = new Entity\OwningManyToManyExtraLazyEntity(); + $owning1->id2 = 'ghi'; + + $owning2 = new Entity\OwningManyToManyExtraLazyEntity(); + $owning2->id2 = 'jkl'; + + $inversed1->associatedEntities->add($owning1); + $owning1->associatedEntities->add($inversed1); + $inversed1->associatedEntities->add($owning2); + $owning2->associatedEntities->add($inversed1); + + $inversed2->associatedEntities->add($owning1); + $owning1->associatedEntities->add($inversed2); + $inversed2->associatedEntities->add($owning2); + $owning2->associatedEntities->add($inversed2); + + $this->_em->persist($inversed1); + $this->_em->persist($inversed2); + $this->_em->persist($owning1); + $this->_em->persist($owning2); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_xref_manytomany_extralazy'); + $conn->executeUpdate('DROP TABLE vct_owning_manytomany_extralazy'); + $conn->executeUpdate('DROP TABLE vct_inversed_manytomany_extralazy'); + } + + public function testThatTheExtraLazyCollectionFromOwningToInversedIsCounted() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $this->assertEquals(2, $owning->associatedEntities->count()); + } + + public function testThatTheExtraLazyCollectionFromInversedToOwningIsCounted() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $this->assertEquals(2, $inversed->associatedEntities->count()); + } + + public function testThatTheExtraLazyCollectionFromOwningToInversedContainsAnEntity() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $this->assertTrue($owning->associatedEntities->contains($inversed)); + } + + public function testThatTheExtraLazyCollectionFromInversedToOwningContainsAnEntity() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $this->assertTrue($inversed->associatedEntities->contains($owning)); + } + + public function testThatTheExtraLazyCollectionFromOwningToInversedContainsAnIndexbyKey() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $this->assertTrue($owning->associatedEntities->containsKey('abc')); + } + + public function testThatTheExtraLazyCollectionFromInversedToOwningContainsAnIndexbyKey() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $this->assertTrue($inversed->associatedEntities->containsKey('ghi')); + } + + public function testThatASliceOfTheExtraLazyCollectionFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $this->assertCount(1, $owning->associatedEntities->slice(0, 1)); + } + + public function testThatASliceOfTheExtraLazyCollectionFromInversedToOwningIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $this->assertCount(1, $inversed->associatedEntities->slice(1, 1)); + } +} diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index b75137f51..0520a15ef 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -242,6 +242,10 @@ abstract class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdForeignKeyEntity' ), + 'vct_manytomany_extralazy' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity' + ), ); /** @@ -457,6 +461,12 @@ abstract class OrmFunctionalTestCase extends OrmTestCase $conn->executeUpdate('DELETE FROM vct_auxiliary'); } + if (isset($this->_usedModelSets['vct_manytomany_extralazy'])) { + $conn->executeUpdate('DELETE FROM vct_xref_manytomany_extralazy'); + $conn->executeUpdate('DELETE FROM vct_owning_manytomany_extralazy'); + $conn->executeUpdate('DELETE FROM vct_inversed_manytomany_extralazy'); + } + $this->_em->clear(); }