From a04113f4101797e4b7552e874d126b2e011692cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Gallego?= Date: Sat, 17 May 2014 12:54:25 +0200 Subject: [PATCH] Add support for optimized contains --- .../Persister/AbstractEntityPersister.php | 5 ++- lib/Doctrine/ORM/LazyCriteriaCollection.php | 17 +++++++++- .../ORM/Persisters/BasicEntityPersister.php | 18 +++++++--- .../ORM/Persisters/EntityPersister.php | 6 ++-- .../ORM/Persisters/OneToManyPersister.php | 2 +- .../Tests/Mocks/EntityPersisterMock.php | 5 ++- .../EntityRepositoryCriteriaTest.php | 33 +++++++++++++++++++ 7 files changed, 75 insertions(+), 11 deletions(-) diff --git a/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php b/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php index b95becba2..de0d9e7cf 100644 --- a/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php @@ -190,8 +190,11 @@ abstract class AbstractEntityPersister implements CachedEntityPersister /** * {@inheritdoc} + * @param object $entity + * @param array $extraConditions + * @return bool */ - public function exists($entity, array $extraConditions = array()) + public function exists($entity, $extraConditions = array()) { if (empty($extraConditions)) { $key = new EntityCacheKey($this->class->rootEntityName, $this->class->getIdentifierValues($entity)); diff --git a/lib/Doctrine/ORM/LazyCriteriaCollection.php b/lib/Doctrine/ORM/LazyCriteriaCollection.php index bb1219696..dcd21419c 100644 --- a/lib/Doctrine/ORM/LazyCriteriaCollection.php +++ b/lib/Doctrine/ORM/LazyCriteriaCollection.php @@ -30,7 +30,7 @@ use Doctrine\ORM\Persisters\EntityPersister; * A lazy collection that allow a fast count when using criteria object * Once count gets executed once without collection being initialized, result * is cached and returned on subsequent calls until collection gets loaded, - * then returning the number of loaded results. + * then returning the number of loaded results. * * @since 2.5 * @author Guilherme Blanco @@ -82,6 +82,21 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl return $this->count = $this->entityPersister->count($this->criteria); } + /** + * Do an optimized search of an element + * + * @param object $element + * @return bool + */ + public function contains($element) + { + if ($this->isInitialized()) { + return $this->collection->contains($element); + } + + return $this->entityPersister->exists($element, $this->criteria); + } + /** * {@inheritDoc} */ diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php index e7a74327c..e7c765901 100644 --- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -1834,8 +1834,11 @@ class BasicEntityPersister implements EntityPersister /** * {@inheritdoc} + * @param object $entity + * @param array $extraConditions + * @return bool */ - public function exists($entity, array $extraConditions = array()) + public function exists($entity, $extraConditions = array()) { $criteria = $this->class->getIdentifierValues($entity); @@ -1843,7 +1846,7 @@ class BasicEntityPersister implements EntityPersister return false; } - if ($extraConditions) { + if (is_array($extraConditions)) { $criteria = array_merge($criteria, $extraConditions); } @@ -1853,12 +1856,19 @@ class BasicEntityPersister implements EntityPersister . $this->getLockTablesSql(null) . ' WHERE ' . $this->getSelectConditionSQL($criteria); + list($params) = $this->expandParameters($criteria); + + if ($extraConditions instanceof Criteria) { + $sql .= ' AND ' . $this->getSelectConditionCriteriaSQL($extraConditions); + list($criteriaParams, $values) = $this->expandCriteriaParameters($extraConditions); + + $params = array_merge($params, $criteriaParams); + } + if ($filterSql = $this->generateFilterConditionSQL($this->class, $alias)) { $sql .= ' AND ' . $filterSql; } - list($params) = $this->expandParameters($criteria); - return (bool) $this->conn->fetchColumn($sql, $params); } diff --git a/lib/Doctrine/ORM/Persisters/EntityPersister.php b/lib/Doctrine/ORM/Persisters/EntityPersister.php index 747ab5802..a3a33cd26 100644 --- a/lib/Doctrine/ORM/Persisters/EntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/EntityPersister.php @@ -319,10 +319,10 @@ interface EntityPersister /** * Checks whether the given managed entity exists in the database. * - * @param object $entity - * @param array $extraConditions + * @param object $entity + * @param array|Criteria $extraConditions * * @return boolean TRUE if the entity exists in the database, FALSE otherwise. */ - public function exists($entity, array $extraConditions = array()); + public function exists($entity, $extraConditions = array()); } diff --git a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php index c53df29d1..e9edcef52 100644 --- a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php @@ -168,7 +168,7 @@ class OneToManyPersister extends AbstractCollectionPersister return (bool) $this->conn->fetchColumn($sql, $params); } - + private function getJoinTableRestrictions(PersistentCollection $coll, $addFilters) { $mapping = $coll->getMapping(); diff --git a/tests/Doctrine/Tests/Mocks/EntityPersisterMock.php b/tests/Doctrine/Tests/Mocks/EntityPersisterMock.php index 41b74607d..7b867888b 100644 --- a/tests/Doctrine/Tests/Mocks/EntityPersisterMock.php +++ b/tests/Doctrine/Tests/Mocks/EntityPersisterMock.php @@ -87,8 +87,11 @@ class EntityPersisterMock extends \Doctrine\ORM\Persisters\BasicEntityPersister /** * {@inheritdoc} + * @param object $entity + * @param array $extraConditions + * @return bool|void */ - public function exists($entity, array $extraConditions = array()) + public function exists($entity, $extraConditions = array()) { $this->existsCalled = true; } diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryCriteriaTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryCriteriaTest.php index 345878849..6a626b3f4 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryCriteriaTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryCriteriaTest.php @@ -21,6 +21,8 @@ namespace Doctrine\Tests\ORM\Functional; use Doctrine\Tests\Models\Generic\DateTimeModel; use Doctrine\Common\Collections\Criteria; +use Doctrine\Tests\Models\Tweet\Tweet; +use Doctrine\Tests\Models\Tweet\User; /** * @author Josiah @@ -30,6 +32,7 @@ class EntityRepositoryCriteriaTest extends \Doctrine\Tests\OrmFunctionalTestCase protected function setUp() { $this->useModelSet('generic'); + $this->useModelSet('tweet'); parent::setUp(); } @@ -165,4 +168,34 @@ class EntityRepositoryCriteriaTest extends \Doctrine\Tests\OrmFunctionalTestCase $date = $dates[0]; $this->assertTrue($dates->isInitialized()); } + + public function testCanContainsWithoutLoadingCollection() + { + $user = new User(); + $user->name = 'Marco'; + $this->_em->persist($user); + $this->_em->flush(); + + $tweet = new Tweet(); + $tweet->author = $user; + $tweet->content = 'Criteria is awesome'; + $this->_em->persist($tweet); + $this->_em->flush(); + + $this->_em->clear(); + + $criteria = new Criteria(); + $criteria->andWhere($criteria->expr()->contains('content', 'Criteria')); + + $user = $this->_em->find('Doctrine\Tests\Models\Tweet\User', $user->id); + $tweets = $user->tweets->matching($criteria); + + $this->assertInstanceOf('Doctrine\ORM\LazyCriteriaCollection', $tweets); + $this->assertFalse($tweets->isInitialized()); + + $tweets->contains($tweet); + $this->assertTrue($tweets->contains($tweet)); + + $this->assertFalse($tweets->isInitialized()); + } }