diff --git a/lib/Doctrine/ORM/Query/TreeWalkerChain.php b/lib/Doctrine/ORM/Query/TreeWalkerChain.php index 4ce356d84..19597ed1a 100644 --- a/lib/Doctrine/ORM/Query/TreeWalkerChain.php +++ b/lib/Doctrine/ORM/Query/TreeWalkerChain.php @@ -25,7 +25,7 @@ namespace Doctrine\ORM\Query; * the AST to influence the final output produced by the last walker. * * @author Roman Borschel - * @since 2.0 + * @since 2.0 */ class TreeWalkerChain implements TreeWalker { @@ -34,7 +34,7 @@ class TreeWalkerChain implements TreeWalker * * @var TreeWalker[] */ - private $_walkers = array(); + private $_walkers; /** * The original Query. @@ -89,6 +89,7 @@ class TreeWalkerChain implements TreeWalker $this->_query = $query; $this->_parserResult = $parserResult; $this->_queryComponents = $queryComponents; + $this->_walkers = new TreeWalkerChainIterator($this, $query, $parserResult); } /** @@ -100,7 +101,7 @@ class TreeWalkerChain implements TreeWalker */ public function addTreeWalker($walkerClass) { - $this->_walkers[] = new $walkerClass($this->_query, $this->_parserResult, $this->_queryComponents); + $this->_walkers[] = $walkerClass; } /** diff --git a/lib/Doctrine/ORM/Query/TreeWalkerChainIterator.php b/lib/Doctrine/ORM/Query/TreeWalkerChainIterator.php new file mode 100644 index 000000000..d693b422a --- /dev/null +++ b/lib/Doctrine/ORM/Query/TreeWalkerChainIterator.php @@ -0,0 +1,126 @@ +treeWalkerChain = $treeWalkerChain; + $this->query = $query; + $this->parserResult = $parserResult; + } + + /** + * {@inheritdoc} + */ + function rewind() + { + return reset($this->walkers); + } + + /** + * {@inheritdoc} + */ + function current() + { + return $this->offsetGet(key($this->walkers)); + } + + /** + * {@inheritdoc} + */ + function key() + { + return key($this->walkers); + } + + /** + * {@inheritdoc} + */ + function next() + { + next($this->walkers); + + return $this->offsetGet(key($this->walkers)); + } + + /** + * {@inheritdoc} + */ + function valid() + { + return key($this->walkers) !== null; + } + + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return isset($this->walkers[$offset]); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + if ($this->offsetExists($offset)) { + return new $this->walkers[$offset]( + $this->query, + $this->parserResult, + $this->treeWalkerChain->getQueryComponents() + ); + } + + return null; + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + if (is_null($offset)) { + $this->walkers[] = $value; + } else { + $this->walkers[$offset] = $value; + } + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + if ($this->offsetExists($offset)) { + unset($this->walkers[$offset]); + } + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Query/CustomTreeWalkersTest.php b/tests/Doctrine/Tests/ORM/Query/CustomTreeWalkersTest.php index b00d43223..c603db6fa 100644 --- a/tests/Doctrine/Tests/ORM/Query/CustomTreeWalkersTest.php +++ b/tests/Doctrine/Tests/ORM/Query/CustomTreeWalkersTest.php @@ -42,7 +42,7 @@ class CustomTreeWalkersTest extends \Doctrine\Tests\OrmTestCase { $query = $this->_em->createQuery($dqlToBeTested); $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $treeWalkers) - ->useQueryCache(false); + ->useQueryCache(false); if ($outputWalker) { $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, $outputWalker); @@ -96,6 +96,15 @@ class CustomTreeWalkersTest extends \Doctrine\Tests\OrmTestCase __NAMESPACE__ . '\\AddUnknownQueryComponentWalker' ); } + + public function testSupportsSeveralHintsQueries() + { + $this->assertSqlGeneration( + 'select u from Doctrine\Tests\Models\CMS\CmsUser u', + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c1_.id AS id4, c1_.country AS country5, c1_.zip AS zip6, c1_.city AS city7, c0_.email_id AS email_id8, c1_.user_id AS user_id9 FROM cms_users c0_ LEFT JOIN cms_addresses c1_ ON c0_.id = c1_.user_id WHERE c0_.id = 1", + array('Doctrine\Tests\ORM\Functional\CustomTreeWalkerJoin', 'Doctrine\Tests\ORM\Functional\CustomTreeWalker') + ); + } } class AddUnknownQueryComponentWalker extends Query\SqlWalker @@ -183,3 +192,43 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter } } } + +class CustomTreeWalkerJoin extends Query\TreeWalkerAdapter +{ + public function walkSelectStatement(Query\AST\SelectStatement $selectStatement) + { + foreach ($selectStatement->fromClause->identificationVariableDeclarations as $identificationVariableDeclaration) { + if ($identificationVariableDeclaration->rangeVariableDeclaration->abstractSchemaName == 'Doctrine\Tests\Models\CMS\CmsUser') { + $identificationVariableDeclaration->joins[] = new Query\AST\Join( + Query\AST\Join::JOIN_TYPE_LEFT, + new Query\AST\JoinAssociationDeclaration( + new Query\AST\JoinAssociationPathExpression( + $identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable, + 'address' + ), + $identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a', + null + ) + ); + $selectStatement->selectClause->selectExpressions[] = + new Query\AST\SelectExpression( + $identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a', + null, + false + ); + $meta1 = $this->_getQuery()->getEntityManager()->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $meta = $this->_getQuery()->getEntityManager()->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $this->setQueryComponent($identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a', + array( + 'metadata' => $meta, + 'parent' => $identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable, + 'relation' => $meta1->getAssociationMapping('address'), + 'map' => null, + 'nestingLevel' => 0, + 'token' => null + ) + ); + } + } + } +}