* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/) * @license http://hobodave.com/license.txt New BSD License */ namespace Doctrine\ORM\Tools\Pagination; use Doctrine\ORM\Query\AST\ArithmeticExpression, Doctrine\ORM\Query\AST\SimpleArithmeticExpression, Doctrine\ORM\Query\TreeWalkerAdapter, Doctrine\ORM\Query\AST\SelectStatement, Doctrine\ORM\Query\AST\PathExpression, Doctrine\ORM\Query\AST\InExpression, Doctrine\ORM\Query\AST\NullComparisonExpression, Doctrine\ORM\Query\AST\InputParameter, Doctrine\ORM\Query\AST\ConditionalPrimary, Doctrine\ORM\Query\AST\ConditionalTerm, Doctrine\ORM\Query\AST\ConditionalExpression, Doctrine\ORM\Query\AST\ConditionalFactor, Doctrine\ORM\Query\AST\WhereClause; /** * Replaces the whereClause of the AST with a WHERE id IN (:foo_1, :foo_2) equivalent * * @category DoctrineExtensions * @package DoctrineExtensions\Paginate * @author David Abdemoulaie * @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/) * @license http://hobodave.com/license.txt New BSD License */ class WhereInWalker extends TreeWalkerAdapter { /** * ID Count hint name */ const HINT_PAGINATOR_ID_COUNT = 'doctrine.id.count'; /** * Primary key alias for query */ const PAGINATOR_ID_ALIAS = 'dpid'; /** * Replaces the whereClause in the AST * * Generates a clause equivalent to WHERE IN (:dpid_1, :dpid_2, ...) * * The parameter namespace (dpid) is defined by * the PAGINATOR_ID_ALIAS * * The total number of parameters is retrieved from * the HINT_PAGINATOR_ID_COUNT query hint * * @param SelectStatement $AST * @return void */ public function walkSelectStatement(SelectStatement $AST) { $rootComponents = array(); foreach ($this->_getQueryComponents() AS $dqlAlias => $qComp) { $isParent = array_key_exists('parent', $qComp) && $qComp['parent'] === null && $qComp['nestingLevel'] == 0 ; if ($isParent) { $rootComponents[] = array($dqlAlias => $qComp); } } if (count($rootComponents) > 1) { throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction"); } $root = reset($rootComponents); $parentName = key($root); $parent = current($root); $pathExpression = new PathExpression( PathExpression::TYPE_STATE_FIELD, $parentName, $parent['metadata']->getSingleIdentifierFieldName() ); $pathExpression->type = PathExpression::TYPE_STATE_FIELD; $count = $this->_getQuery()->getHint(self::HINT_PAGINATOR_ID_COUNT); if ($count > 0) { $arithmeticExpression = new ArithmeticExpression(); $arithmeticExpression->simpleArithmeticExpression = new SimpleArithmeticExpression( array($pathExpression) ); $expression = new InExpression($arithmeticExpression); $ns = self::PAGINATOR_ID_ALIAS; for ($i = 1; $i <= $count; $i++) { $expression->literals[] = new InputParameter(":{$ns}_$i"); } } else { $expression = new NullComparisonExpression($pathExpression); $expression->not = false; } $conditionalPrimary = new ConditionalPrimary; $conditionalPrimary->simpleConditionalExpression = $expression; if ($AST->whereClause) { if ($AST->whereClause->conditionalExpression instanceof ConditionalTerm) { $AST->whereClause->conditionalExpression->conditionalFactors[] = $conditionalPrimary; } elseif ($AST->whereClause->conditionalExpression instanceof ConditionalPrimary) { $AST->whereClause->conditionalExpression = new ConditionalExpression(array( new ConditionalTerm(array( $AST->whereClause->conditionalExpression, $conditionalPrimary )) )); } elseif ($AST->whereClause->conditionalExpression instanceof ConditionalExpression || $AST->whereClause->conditionalExpression instanceof ConditionalFactor ) { $tmpPrimary = new ConditionalPrimary; $tmpPrimary->conditionalExpression = $AST->whereClause->conditionalExpression; $AST->whereClause->conditionalExpression = new ConditionalTerm(array( $tmpPrimary, $conditionalPrimary )); } } else { $AST->whereClause = new WhereClause( new ConditionalExpression(array( new ConditionalTerm(array( $conditionalPrimary )) )) ); } } }