From 82be4bf0235bf3796f55cd23c8a6fa1973cee540 Mon Sep 17 00:00:00 2001 From: guilhermeblanco Date: Sun, 19 Jul 2009 16:18:51 +0000 Subject: [PATCH] [2.0] More work on TODO items. Fixed grammar rule that was incorrect. --- .../ORM/Query/AST/AggregateExpression.php | 21 ++++- lib/Doctrine/ORM/Query/AST/OrderByItem.php | 39 +++++--- lib/Doctrine/ORM/Query/Parser.php | 89 ++++++++++++------- lib/Doctrine/ORM/Query/SqlWalker.php | 6 +- 4 files changed, 106 insertions(+), 49 deletions(-) diff --git a/lib/Doctrine/ORM/Query/AST/AggregateExpression.php b/lib/Doctrine/ORM/Query/AST/AggregateExpression.php index 17293b903..97da4d7a6 100644 --- a/lib/Doctrine/ORM/Query/AST/AggregateExpression.php +++ b/lib/Doctrine/ORM/Query/AST/AggregateExpression.php @@ -1,7 +1,22 @@ . */ namespace Doctrine\ORM\Query\AST; diff --git a/lib/Doctrine/ORM/Query/AST/OrderByItem.php b/lib/Doctrine/ORM/Query/AST/OrderByItem.php index f452419a1..cd68230cf 100644 --- a/lib/Doctrine/ORM/Query/AST/OrderByItem.php +++ b/lib/Doctrine/ORM/Query/AST/OrderByItem.php @@ -1,30 +1,49 @@ . */ namespace Doctrine\ORM\Query\AST; /** - * OrderByItem ::= StateFieldPathExpression ["ASC" | "DESC"] + * AST node for the following grammar rule: * - * @author robo + * OrderByItem ::= (ResultVariable | StateFieldPathExpression) ["ASC" | "DESC"] + * + * @author Guilherme Blanco + * @author Roman Borschel + * @since 2.0 */ class OrderByItem extends Node { - private $_pathExpr; + private $_expr; private $_asc; private $_desc; - public function __construct($pathExpr) + public function __construct($expr) { - $this->_pathExpr = $pathExpr; + $this->_expr = $expr; } - public function getStateFieldPathExpression() + public function getExpression() { - return $this->_pathExpr; + return $this->_expr; } public function setAsc($bool) diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 378ffbfc4..e39e13b93 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -627,8 +627,7 @@ class Parser /** * SelectExpression ::= * IdentificationVariable | StateFieldPathExpression | - * (AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable] | - * Function + * (AggregateExpression | "(" Subselect ")" | Function) [["AS"] FieldAliasIdentificationVariable] */ public function SelectExpression() { @@ -657,8 +656,7 @@ class Parser } if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { - $this->match(Lexer::T_IDENTIFIER); - $fieldIdentificationVariable = $this->_lexer->token['value']; + $fieldIdentificationVariable = $this->ResultVariable(); } } else { // Deny hydration of partial objects if doctrine.forcePartialLoad query hint not defined @@ -675,6 +673,16 @@ class Parser return new AST\SelectExpression($expression, $fieldIdentificationVariable); } + + /** + * ResultVariable ::= identifier + */ + public function ResultVariable() + { + $this->match(Lexer::T_IDENTIFIER); + + return $this->_lexer->token['value']; + } /** * IdentificationVariable ::= identifier @@ -1251,24 +1259,38 @@ class Parser } /** - * OrderByItem ::= ResultVariable | StateFieldPathExpression ["ASC" | "DESC"] + * OrderByItem ::= (ResultVariable | StateFieldPathExpression) ["ASC" | "DESC"] * - * @todo Implementation incomplete for OrderByItem. + * @todo Support general SingleValuedPathExpression instead of only StateFieldPathExpression. */ public function OrderByItem() { - $item = new AST\OrderByItem($this->StateFieldPathExpression()); + // We need to check if we are in a ResultVariable or StateFieldPathExpression + $glimpse = $this->_lexer->glimpse(); + + if ($glimpse['value'] != '.') { + $expr = $this->ResultVariable(); + + // @todo Check if ResultVariable is defined somewhere + } else { + $expr = $this->StateFieldPathExpression(); + } + + $item = new AST\OrderByItem($expr); if ($this->_lexer->isNextToken(Lexer::T_ASC)) { $this->match(Lexer::T_ASC); $item->setAsc(true); - } else if ($this->_lexer->isNextToken(Lexer::T_DESC)) { - $this->match(Lexer::T_DESC); - $item->setDesc(true); - } else { - $item->setDesc(true); + + return $item; } - + + if ($this->_lexer->isNextToken(Lexer::T_DESC)) { + $this->match(Lexer::T_DESC); + } + + $item->setDesc(true); + return $item; } @@ -1338,37 +1360,38 @@ class Parser $condPrimary = new AST\ConditionalPrimary; if ($this->_lexer->isNextToken('(')) { - // Peek beyond the matching closing paranthesis ')' - $numUnmatched = 1; $peek = $this->_lexer->peek(); - - while ($numUnmatched > 0) { - if ($peek['value'] == ')') { - --$numUnmatched; - } else if ($peek['value'] == '(') { - ++$numUnmatched; + + // We need to inner inspect for a subselect (ArithmeticExpression) + if ($peek['type'] != Lexer::T_SELECT) { + // Peek beyond and not until matching closing parenthesis + $arithmeticOps = array("+", "-", "*", "/"); + $numUnmatched = 1; + + // While not found a closing matched parenthesis and a matched arithmetic operator + while ($numUnmatched > 0 && ! in_array($peek['value'], $arithmeticOps)) { + if ($peek['value'] == ')') { + --$numUnmatched; + } else if ($peek['value'] == '(') { + ++$numUnmatched; + } + + $peek = $this->_lexer->peek(); } - - $peek = $this->_lexer->peek(); } - - $this->_lexer->resetPeek(); - - //TODO: This is not complete, what about LIKE/BETWEEN/...etc? - $comparisonOps = array("=", "<", "<=", "<>", ">", ">=", "!="); - - if (in_array($peek['value'], $comparisonOps)) { + + // Check if unmatched parenthesis is > 0, then we found a matching arithmetic operator + if ($numUnmatched > 0) { $condPrimary->setSimpleConditionalExpression($this->SimpleConditionalExpression()); } else { $this->match('('); - $conditionalExpression = $this->ConditionalExpression(); + $condPrimary->setConditionalExpression($this->ConditionalExpression()); $this->match(')'); - $condPrimary->setConditionalExpression($conditionalExpression); } } else { $condPrimary->setSimpleConditionalExpression($this->SimpleConditionalExpression()); } - + return $condPrimary; } diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index c00376467..7ca38d8ec 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -240,9 +240,9 @@ class SqlWalker implements TreeWalker public function walkOrderByItem($orderByItem) { //TODO: support general SingleValuedPathExpression, not just state field - $pathExpr = $orderByItem->getStateFieldPathExpression(); - $parts = $pathExpr->getParts(); - $dqlAlias = $pathExpr->getIdentificationVariable(); + $expr = $orderByItem->getExpression(); + $parts = $expr->getParts(); + $dqlAlias = $expr->getIdentificationVariable(); $qComp = $this->_queryComponents[$dqlAlias]; $columnName = $qComp['metadata']->getColumnName($parts[0]); $sql = $this->getSqlTableAlias($qComp['metadata']->getTableName() . $dqlAlias) . '.' . $columnName;