diff --git a/UPGRADE.md b/UPGRADE.md index fe5f52528..0aacaa603 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -28,6 +28,20 @@ Now parenthesis are considered, the previous DQL will generate: SELECT 100 / (2 * 2) FROM my_entity +## Compatibility Bugfix in PersistentCollection#matching() breaks BC + +In Doctrine 2.3 it was possible to use the new ``matching($criteria)`` +functionality by adding constraints for assocations based on ID: + + Criteria::expr()->eq('association', $assocation->getId()); + +This functionality does not work on InMemory collections however, because +in memory criteria compares object values based on reference. +As of 2.4 the above code will throw an exception. You need to change +offending code to pass the ``$assocation`` reference directly: + + Criteria::expr()->eq('association', $assocation); + # Upgrade to 2.3 ## EntityManager#find() not calls EntityRepository#find() anymore diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index b644ec154..53ba1c1f2 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -850,12 +850,8 @@ final class PersistentCollection implements Collection, Selectable throw new \RuntimeException("Matching Criteria on PersistentCollection only works on OneToMany associations at the moment."); } - $id = $this->em - ->getClassMetadata(get_class($this->owner)) - ->getSingleIdReflectionProperty() - ->getValue($this->owner); $builder = Criteria::expr(); - $ownerExpression = $builder->eq($this->backRefFieldName, $id); + $ownerExpression = $builder->eq($this->backRefFieldName, $this->owner); $expression = $criteria->getWhereExpression(); $expression = $expression ? $builder->andX($expression, $ownerExpression) : $ownerExpression; diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php index 96f144934..8f921f2b8 100644 --- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -1583,7 +1583,7 @@ class BasicEntityPersister return ''; } - $visitor = new SqlExpressionVisitor($this); + $visitor = new SqlExpressionVisitor($this, $this->class); return $visitor->dispatch($expression); } diff --git a/lib/Doctrine/ORM/Persisters/PersisterException.php b/lib/Doctrine/ORM/Persisters/PersisterException.php new file mode 100644 index 000000000..111455e5b --- /dev/null +++ b/lib/Doctrine/ORM/Persisters/PersisterException.php @@ -0,0 +1,20 @@ +persister = $persister; + $this->classMetadata = $classMetadata; } /** @@ -57,6 +65,10 @@ class SqlExpressionVisitor extends ExpressionVisitor $field = $comparison->getField(); $value = $comparison->getValue()->getValue(); // shortcut for walkValue() + if (isset($this->classMetadata->associationMappings[$field]) && ! is_object($value)) { + throw PersisterException::matchingAssocationFieldRequiresObject($this->classMetadata->name, $field); + } + return $this->persister->getSelectConditionStatementSQL($field, $value, null, $comparison->getOperator()); } diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php index b45eee3d0..48e5f3389 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -7,8 +7,7 @@ use Doctrine\Tests\Models\CMS\CmsEmail; use Doctrine\Tests\Models\CMS\CmsAddress; use Doctrine\Tests\Models\CMS\CmsPhonenumber; use Doctrine\Common\Collections\Criteria; - -require_once __DIR__ . '/../../TestInit.php'; +use Doctrine\Common\Collections\ArrayCollection; /** * @author robo @@ -781,6 +780,29 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals(4, count($users)); } + /** + * @group DDC-2430 + */ + public function testMatchingCriteriaAssocationByObjectInMemory() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId); + + $criteria = new Criteria( + Criteria::expr()->gte('user', $user) + ); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $addresses = $repository->matching($criteria); + + $this->assertEquals(1, count($addresses)); + + $addresses = new ArrayCollection($repository->findAll()); + + $this->assertEquals(1, count($addresses->matching($criteria))); + } + public function testMatchingCriteriaContainsComparison() { $this->loadFixture(); diff --git a/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php b/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php index 4254ce3d2..1704c8b4e 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php @@ -343,17 +343,32 @@ class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase $repository = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyContract"); $contracts = $repository->matching(new Criteria( - Criteria::expr()->eq('salesPerson', $this->salesPerson->getId()) + Criteria::expr()->eq('salesPerson', $this->salesPerson) )); $this->assertEquals(3, count($contracts)); $repository = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyFixContract"); $contracts = $repository->matching(new Criteria( - Criteria::expr()->eq('salesPerson', $this->salesPerson->getId()) + Criteria::expr()->eq('salesPerson', $this->salesPerson) )); $this->assertEquals(1, count($contracts)); } + /** + * @group DDC-2430 + */ + public function testMatchingNonObjectOnAssocationThrowsException() + { + $this->loadFullFixture(); + + $repository = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyContract"); + + $this->setExpectedException('Doctrine\ORM\Persisters\PersisterException', 'annot match on Doctrine\Tests\Models\Company\CompanyContract::salesPerson with a non-object value.'); + $contracts = $repository->matching(new Criteria( + Criteria::expr()->eq('salesPerson', $this->salesPerson->getId()) + )); + } + /** * @group DDC-834 */