CountWalker.php 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. <?php
  2. /**
  3. * Doctrine ORM
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * If you did not receive a copy of the license and are unable to
  10. * obtain it through the world-wide-web, please send an email
  11. * to kontakt@beberlei.de so I can send you a copy immediately.
  12. */
  13. namespace Doctrine\ORM\Tools\Pagination;
  14. use Doctrine\ORM\Query\TreeWalkerAdapter,
  15. Doctrine\ORM\Query\AST\SelectStatement,
  16. Doctrine\ORM\Query\AST\SelectExpression,
  17. Doctrine\ORM\Query\AST\PathExpression,
  18. Doctrine\ORM\Query\AST\AggregateExpression;
  19. /**
  20. * Replaces the selectClause of the AST with a COUNT statement
  21. *
  22. * @category DoctrineExtensions
  23. * @package DoctrineExtensions\Paginate
  24. * @author David Abdemoulaie <dave@hobodave.com>
  25. * @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
  26. * @license http://hobodave.com/license.txt New BSD License
  27. */
  28. class CountWalker extends TreeWalkerAdapter
  29. {
  30. /**
  31. * Distinct mode hint name
  32. */
  33. const HINT_DISTINCT = 'doctrine_paginator.distinct';
  34. /**
  35. * Walks down a SelectStatement AST node, modifying it to retrieve a COUNT
  36. *
  37. * @param SelectStatement $AST
  38. * @return void
  39. */
  40. public function walkSelectStatement(SelectStatement $AST)
  41. {
  42. $rootComponents = array();
  43. foreach ($this->_getQueryComponents() AS $dqlAlias => $qComp) {
  44. $isParent = array_key_exists('parent', $qComp)
  45. && $qComp['parent'] === null
  46. && $qComp['nestingLevel'] == 0
  47. ;
  48. if ($isParent) {
  49. $rootComponents[] = array($dqlAlias => $qComp);
  50. }
  51. }
  52. if (count($rootComponents) > 1) {
  53. throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
  54. }
  55. $root = reset($rootComponents);
  56. $parentName = key($root);
  57. $parent = current($root);
  58. $pathExpression = new PathExpression(
  59. PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName,
  60. $parent['metadata']->getSingleIdentifierFieldName()
  61. );
  62. $pathExpression->type = PathExpression::TYPE_STATE_FIELD;
  63. $distinct = $this->_getQuery()->getHint(self::HINT_DISTINCT);
  64. $AST->selectClause->selectExpressions = array(
  65. new SelectExpression(
  66. new AggregateExpression('count', $pathExpression, $distinct), null
  67. )
  68. );
  69. // ORDER BY is not needed, only increases query execution through unnecessary sorting.
  70. $AST->orderByClause = null;
  71. }
  72. }