diff --git a/lib/Doctrine/ORM/Tools/Pagination/Paginator.php b/lib/Doctrine/ORM/Tools/Pagination/Paginator.php index 087a17513..c5b0b3686 100755 --- a/lib/Doctrine/ORM/Tools/Pagination/Paginator.php +++ b/lib/Doctrine/ORM/Tools/Pagination/Paginator.php @@ -19,6 +19,7 @@ namespace Doctrine\ORM\Tools\Pagination; +use Doctrine\ORM\Query\Parser; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Query; use Doctrine\ORM\Query\ResultSetMapping; @@ -118,31 +119,8 @@ class Paginator implements \Countable, \IteratorAggregate public function count() { if ($this->count === null) { - /* @var $countQuery Query */ - $countQuery = $this->cloneQuery($this->query); - - if ( ! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) { - $countQuery->setHint(CountWalker::HINT_DISTINCT, true); - } - - if ($this->useOutputWalker($countQuery)) { - $platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win - - $rsm = new ResultSetMapping(); - $rsm->addScalarResult($platform->getSQLResultCasing('dctrn_count'), 'count'); - - $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker'); - $countQuery->setResultSetMapping($rsm); - } else { - $this->appendTreeWalker($countQuery, 'Doctrine\ORM\Tools\Pagination\CountWalker'); - } - - $countQuery->setFirstResult(null)->setMaxResults(null); - try { - $data = $countQuery->getScalarResult(); - $data = array_map('current', $data); - $this->count = array_sum($data); + $this->count = array_sum(array_map('current', $this->getCountQuery()->getScalarResult())); } catch(NoResultException $e) { $this->count = 0; } @@ -252,4 +230,50 @@ class Paginator implements \Countable, \IteratorAggregate $hints[] = $walkerClass; $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $hints); } + + /** + * Returns Query prepared to count. + * + * @return Query + */ + private function getCountQuery() + { + /* @var $countQuery Query */ + $countQuery = $this->cloneQuery($this->query); + + if ( ! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) { + $countQuery->setHint(CountWalker::HINT_DISTINCT, true); + } + + if ($this->useOutputWalker($countQuery)) { + $platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win + + $rsm = new ResultSetMapping(); + $rsm->addScalarResult($platform->getSQLResultCasing('dctrn_count'), 'count'); + + $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker'); + $countQuery->setResultSetMapping($rsm); + } else { + $this->appendTreeWalker($countQuery, 'Doctrine\ORM\Tools\Pagination\CountWalker'); + } + + $countQuery->setFirstResult(null)->setMaxResults(null); + + $parser = new Parser($countQuery); + $parameterMappings = $parser->parse()->getParameterMappings(); + /* @var $parameters \Doctrine\Common\Collections\Collection|\Doctrine\ORM\Query\Parameter[] */ + $parameters = $countQuery->getParameters(); + + foreach ($parameters as $key => $parameter) { + $parameterName = $parameter->getName(); + + if( ! (isset($parameterMappings[$parameterName]) || array_key_exists($parameterName, $parameterMappings))) { + unset($parameters[$key]); + } + } + + $countQuery->setParameters($parameters); + + return $countQuery; + } } diff --git a/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php b/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php index bf9e4a685..303bf4fe8 100644 --- a/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php @@ -11,6 +11,7 @@ use Doctrine\Tests\Models\CMS\CmsGroup; use Doctrine\Tests\Models\CMS\CmsArticle; use Doctrine\Tests\Models\CMS\CmsComment; use Doctrine\ORM\Tools\Pagination\Paginator; +use ReflectionMethod; /** * @group DDC-1613 @@ -150,6 +151,36 @@ class PaginationTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertCount(1, $paginator->getIterator()); $this->assertEquals(1, $paginator->count()); } + + public function testCountQueryStripsParametersInSelect() + { + $query = $this->_em->createQuery( + 'SELECT u, (CASE WHEN u.id < :vipMaxId THEN 1 ELSE 0 END) AS hidden promotedFirst + FROM Doctrine\\Tests\\Models\\CMS\\CmsUser u + WHERE u.id < :id or 1=1' + ); + $query->setParameter('vipMaxId', 10); + $query->setParameter('id', 100); + $query->setFirstResult(null)->setMaxResults(null); + + $paginator = new Paginator($query); + + $getCountQuery = new ReflectionMethod($paginator, 'getCountQuery'); + + $getCountQuery->setAccessible(true); + + $this->assertCount(2, $getCountQuery->invoke($paginator)->getParameters()); + $this->assertCount(3, $paginator); + + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Query\SqlWalker'); + + $paginator = new Paginator($query); + + // if select part of query is replaced with count(...) paginator should remove + // parameters from query object not used in new query. + $this->assertCount(1, $getCountQuery->invoke($paginator)->getParameters()); + $this->assertCount(3, $paginator); + } public function populate() {