Skip to content

Commit

Permalink
Merge branch 'hotfix/#1188-support-count-queries-with-parameters-in-r…
Browse files Browse the repository at this point in the history
…emoved-query-parts-2.4-backport' into 2.4

Merge #1188 into 2.4
  • Loading branch information
Ocramius committed Nov 28, 2014
2 parents 3cef0fd + df99353 commit c701e8b
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 24 deletions.
72 changes: 48 additions & 24 deletions lib/Doctrine/ORM/Tools/Pagination/Paginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -118,31 +119,8 @@ 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);

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;
}
Expand Down Expand Up @@ -249,4 +227,50 @@ private function appendTreeWalker(Query $query, $walkerClass)
$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;
}
}
31 changes: 31 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/PaginationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Doctrine\Tests\Models\CMS\CmsArticle;
use Doctrine\Tests\Models\CMS\CmsComment;
use Doctrine\ORM\Tools\Pagination\Paginator;
use ReflectionMethod;

/**
* @group DDC-1613
Expand Down Expand Up @@ -150,6 +151,36 @@ public function testQueryWalkerIsKept()
$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()
{
Expand Down

0 comments on commit c701e8b

Please sign in to comment.