diff --git a/lib/Doctrine/ORM/Tools/Pagination/Paginator.php b/lib/Doctrine/ORM/Tools/Pagination/Paginator.php index 087a1751346..dc4801a46c8 100755 --- a/lib/Doctrine/ORM/Tools/Pagination/Paginator.php +++ b/lib/Doctrine/ORM/Tools/Pagination/Paginator.php @@ -118,26 +118,7 @@ public function setUseOutputWalkers($useOutputWalkers) 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); + $countQuery = $this->getCountQuery(); try { $data = $countQuery->getScalarResult(); @@ -150,6 +131,44 @@ public function count() return $this->count; } + /** + * Returns Query prepared to count. + * + * @return Query + */ + public 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 Query\Parser($countQuery); + $parameterMappings = $parser->parse()->getParameterMappings(); + $parameters = $countQuery->getParameters(); + foreach ($parameters as $k => $param){ + if( ! array_key_exists($param->getName(), $parameterMappings)) { + $parameters->remove($k); + } + } + $countQuery->setParameters($parameters); + return $countQuery; + } /** * {@inheritdoc} diff --git a/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php b/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php index bf9e4a68589..fd9b2d08da0 100644 --- a/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php @@ -150,6 +150,29 @@ public function testQueryWalkerIsKept() $this->assertCount(1, $paginator->getIterator()); $this->assertEquals(1, $paginator->count()); } + + public function testCountQuery_ParametersInSelect() + { + /** @var $query Query */ + $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 ORDER BY promotedFirst' + ); + $query->setParameter('vipMaxId', 10); + $query->setParameter('id', 100); + $query->setFirstResult(null)->setMaxResults(null); + + $paginator = new Paginator($query); + $countQuery = $paginator->getCountQuery(); + $this->assertEquals(2, count($countQuery->getParameters())); + $this->assertEquals(3, $paginator->count()); + + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Query\SqlWalker'); + $paginator = new Paginator($query); + $countQuery = $paginator->getCountQuery(); + //if select part of query is replaced with count(...) paginator should remove parameters from query object not used in new query. + $this->assertEquals(1, count($countQuery->getParameters())); + $this->assertEquals(3, $paginator->count()); + } public function populate() {