diff --git a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php index 34498a325..33dab21d1 100644 --- a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php @@ -192,7 +192,7 @@ class ManyToManyPersister extends AbstractCollectionPersister */ public function count(PersistentCollection $coll) { - $mapping = $coll->getMapping(); + $mapping = $filterMapping = $coll->getMapping(); $class = $this->_em->getClassMetadata($mapping['sourceEntity']); $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner()); @@ -218,7 +218,7 @@ class ManyToManyPersister extends AbstractCollectionPersister : $id[$class->fieldNames[$joinColumns[$joinTableColumn]]]; } - list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping); + list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping); if ($filterSql) { $whereClauses[] = $filterSql; } @@ -295,7 +295,7 @@ class ManyToManyPersister extends AbstractCollectionPersister private function getJoinTableRestrictions(PersistentCollection $coll, $element, $addFilters) { $uow = $this->_em->getUnitOfWork(); - $mapping = $coll->getMapping(); + $mapping = $filterMapping = $coll->getMapping(); if ( ! $mapping['isOwningSide']) { $sourceClass = $this->_em->getClassMetadata($mapping['targetEntity']); @@ -332,7 +332,7 @@ class ManyToManyPersister extends AbstractCollectionPersister } if ($addFilters) { - list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping); + list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping); if ($filterSql) { $quotedJoinTable .= ' t ' . $joinTargetEntitySQL; $whereClauses[] = $filterSql; @@ -351,13 +351,21 @@ class ManyToManyPersister extends AbstractCollectionPersister * have to join in the actual entities table leading to additional * JOIN. * - * @param array $targetEntity Array containing mapping information. + * @param array $mapping Array containing mapping information. * * @return string The SQL query part to add to a query. */ public function getFilterSql($mapping) { $targetClass = $this->_em->getClassMetadata($mapping['targetEntity']); + + if ($mapping['isOwningSide']) { + $joinColumns = $mapping['relationToTargetKeyColumns']; + } else { + $mapping = $targetClass->associationMappings[$mapping['mappedBy']]; + $joinColumns = $mapping['relationToSourceKeyColumns']; + } + $targetClass = $this->_em->getClassMetadata($targetClass->rootEntityName); // A join is needed if there is filtering on the target entity @@ -368,7 +376,7 @@ class ManyToManyPersister extends AbstractCollectionPersister . ' ON'; $joinTargetEntitySQLClauses = array(); - foreach ($mapping['relationToTargetKeyColumns'] as $joinTableColumn => $targetTableColumn) { + foreach ($joinColumns as $joinTableColumn => $targetTableColumn) { $joinTargetEntitySQLClauses[] = ' t.' . $joinTableColumn . ' = ' . 'te.' . $targetTableColumn; } diff --git a/tests/Doctrine/Tests/Models/Company/CompanyContract.php b/tests/Doctrine/Tests/Models/Company/CompanyContract.php index 221bf1cd8..70dd2fcb4 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyContract.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyContract.php @@ -32,7 +32,7 @@ abstract class CompanyContract private $completed = false; /** - * @ManyToMany(targetEntity="CompanyEmployee") + * @ManyToMany(targetEntity="CompanyEmployee", inversedBy="contracts") * @JoinTable(name="company_contract_employees", * joinColumns={@JoinColumn(name="contract_id", referencedColumnName="id", onDelete="CASCADE")}, * inverseJoinColumns={@JoinColumn(name="employee_id", referencedColumnName="id")} @@ -86,4 +86,4 @@ abstract class CompanyContract } abstract public function calculatePrice(); -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/Models/Company/CompanyEmployee.php b/tests/Doctrine/Tests/Models/Company/CompanyEmployee.php index 5e050f948..a9235c321 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyEmployee.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyEmployee.php @@ -23,6 +23,11 @@ class CompanyEmployee extends CompanyPerson */ private $startDate; + /** + * @ManyToMany(targetEntity="CompanyContract", mappedBy="engineers", fetch="EXTRA_LAZY") + */ + public $contracts; + public function getSalary() { return $this->salary; } @@ -46,4 +51,4 @@ class CompanyEmployee extends CompanyPerson public function setStartDate($date) { $this->startDate = $date; } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php b/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php index 11f966f17..976506d7c 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php @@ -18,6 +18,15 @@ class CompanyFlexContract extends CompanyContract */ private $pricePerHour = 0; + /** + * @ManyToMany(targetEntity="CompanyManager", inversedBy="managedContracts") + * @JoinTable(name="company_contract_managers", + * joinColumns={@JoinColumn(name="contract_id", referencedColumnName="id", onDelete="CASCADE")}, + * inverseJoinColumns={@JoinColumn(name="employee_id", referencedColumnName="id")} + * ) + */ + private $managers; + public function calculatePrice() { return $this->hoursWorked * $this->pricePerHour; @@ -42,4 +51,18 @@ class CompanyFlexContract extends CompanyContract { $this->pricePerHour = $pricePerHour; } -} \ No newline at end of file + public function getManagers() + { + return $this->managers; + } + + public function addManager(CompanyManager $manager) + { + $this->managers[] = $manager; + } + + public function removeManager(CompanyManager $manager) + { + $this->managers->removeElement($manager); + } +} diff --git a/tests/Doctrine/Tests/Models/Company/CompanyManager.php b/tests/Doctrine/Tests/Models/Company/CompanyManager.php index e0d39dfcf..aec9a77ae 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyManager.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyManager.php @@ -19,6 +19,11 @@ class CompanyManager extends CompanyEmployee */ private $car; + /** + * @ManyToMany(targetEntity="CompanyFlexContract", mappedBy="managers", fetch="EXTRA_LAZY") + */ + public $managedContracts; + public function getTitle() { return $this->title; } @@ -34,4 +39,4 @@ class CompanyManager extends CompanyEmployee public function setCar(CompanyCar $car) { $this->car = $car; } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php b/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php index 98b3fafd4..6444877d0 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php @@ -34,6 +34,7 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase { private $userId, $userId2, $articleId, $articleId2; private $groupId, $groupId2; + private $managerId, $contractId1, $contractId2; public function setUp() { @@ -655,12 +656,89 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase $contract4 = new CompanyFlexContract; $contract4->markCompleted(); + $manager = new CompanyManager; + $manager->setName('Alexander'); + $manager->setSalary(42); + $manager->setDepartment('Doctrine'); + $manager->setTitle('Filterer'); + + $contract1->addManager($manager); + $contract2->addManager($manager); + $contract3->addManager($manager); + $contract4->addManager($manager); + + $this->_em->persist($manager); $this->_em->persist($contract1); $this->_em->persist($contract2); $this->_em->persist($contract3); $this->_em->persist($contract4); $this->_em->flush(); $this->_em->clear(); + + $this->managerId = $manager->getId(); + $this->contractId1 = $contract1->getId(); + $this->contractId2 = $contract2->getId(); + } + + private function useCompletedContractFilter() + { + $conf = $this->_em->getConfiguration(); + $conf->addFilter("completed_contract", "\Doctrine\Tests\ORM\Functional\CompletedContractFilter"); + $this->_em->getFilters() + ->enable("completed_contract") + ->setParameter("completed", true, DBALType::BOOLEAN); + } + + public function testManyToMany_ExtraLazyCountWithFilterOnSTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertEquals(4, count($manager->managedContracts)); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertEquals(2, count($manager->managedContracts)); + } + + public function testManyToMany_ExtraLazyContainsWithFilterOnSTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + $contract1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId1); + $contract2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId2); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertTrue($manager->managedContracts->contains($contract1)); + $this->assertTrue($manager->managedContracts->contains($contract2)); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertFalse($manager->managedContracts->contains($contract1)); + $this->assertTrue($manager->managedContracts->contains($contract2)); + } + + public function testManyToMany_ExtraLazySliceWithFilterOnSTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertEquals(4, count($manager->managedContracts->slice(0, 10))); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertEquals(2, count($manager->managedContracts->slice(0, 10))); } }