1
0
mirror of synced 2024-12-13 06:46:03 +03:00

DQL Parser work. Getting some first tests back running. Reorganizing all parser rules into the Parser itself.

This commit is contained in:
romanb 2009-01-19 18:40:12 +00:00
parent f0a302ec8d
commit 602c6d973e
39 changed files with 1460 additions and 524 deletions

View File

@ -118,4 +118,3 @@ class Doctrine_ORM_Mapping_OneToManyMapping extends Doctrine_ORM_Mapping_Associa
}
?>

View File

@ -31,11 +31,4 @@
*/
abstract class Doctrine_ORM_Query_AST
{
protected $_parserResult = null;
public function __construct(Doctrine_ORM_Query_ParserResult $parserResult)
{
$this->_parserResult = $parserResult;
}
}

View File

@ -0,0 +1,40 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of AggregateExpression
*
* @author robo
*/
class Doctrine_ORM_Query_AST_AggregateExpression extends Doctrine_ORM_Query_AST
{
private $_functionName;
private $_pathExpression;
private $_isDistinct = false; // Some aggregate expressions support distinct, eg COUNT
public function __construct($functionName, $pathExpression, $isDistinct)
{
$this->_functionName = $functionName;
$this->_pathExpression = $pathExpression;
$this->_isDistinct = $isDistinct;
}
public function getPathExpression()
{
return $this->_pathExpression;
}
public function isDistinct()
{
return $this->_isDistinct;
}
public function getFunctionName()
{
return $this->_functionName;
}
}

View File

@ -0,0 +1,16 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of ComparisonExpression
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ComparisonExpression extends Doctrine_ORM_Query_AST
{
}

View File

@ -0,0 +1,26 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ConditionalExpression extends Doctrine_ORM_Query_AST
{
private $_conditionalTerms = array();
public function __construct(array $conditionalTerms)
{
$this->_conditionalTerms = $conditionalTerms;
}
public function getConditionalTerms()
{
return $this->_conditionalTerm;
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* ConditionalFactor ::= ["NOT"] ConditionalPrimary
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ConditionalFactor extends Doctrine_ORM_Query_AST
{
private $_not = false;
private $_conditionalPrimary;
public function __construct($conditionalPrimary, $not = false)
{
$this->_conditionalPrimary = $conditionalPrimary;
$this->_not = $not;
}
public function isNot()
{
return $this->_not;
}
public function getConditionalPrimary()
{
return $this->_conditionalPrimary;
}
}

View File

@ -0,0 +1,37 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ConditionalPrimary extends Doctrine_ORM_Query_AST
{
private $_simpleConditionalExpression;
private $_conditionalExpression;
public function setSimpleConditionalExpression($simpleConditionalExpr)
{
$this->_simpleConditionalExpression = $simpleConditionalExpr;
}
public function setConditionalExpression($conditionalExpr)
{
$this->_conditionalExpression = $conditionalExpr;
}
public function getSimpleConditionalExpression()
{
return $this->_simpleConditionalExpression;
}
public function getConditionalExpression()
{
return $this->_conditionalExpression;
}
}

View File

@ -0,0 +1,26 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ConditionalTerm extends Doctrine_ORM_Query_AST
{
private $_conditionalFactors = array();
public function __construct(array $conditionalFactors)
{
$this->_conditionalFactors = $conditionalFactors;
}
public function getConditionalFactors()
{
return $this->_conditionalFactors;
}
}

View File

@ -31,22 +31,11 @@
class Doctrine_ORM_Query_AST_FromClause extends Doctrine_ORM_Query_AST
{
protected $_identificationVariableDeclarations = array();
/* Setters */
public function addIdentificationVariableDeclaration($identificationVariableDeclaration)
public function __construct(array $identificationVariableDeclarations)
{
$this->_identificationVariableDeclarations[] = $identificationVariableDeclaration;
}
public function setIdentificationVariableDeclarations($identificationVariableDeclarations, $append = false)
{
$this->_selectExpressions = ($append === true)
? array_merge($this->_identificationVariableDeclarations, $identificationVariableDeclarations)
: $identificationVariableDeclarations;
}
$this->_identificationVariableDeclarations = $identificationVariableDeclarations;
}
/* Getters */
public function getIdentificationVariableDeclarations()

View File

@ -0,0 +1,26 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of GroupByClause
*
* @author robo
*/
class Doctrine_ORM_Query_AST_GroupByClause extends Doctrine_ORM_Query_AST
{
private $_groupByItems = array();
public function __construct(array $groupByItems)
{
$this->_groupByItems = $groupByItems;
}
public function getGroupByItems()
{
return $this->_groupByItems;
}
}

View File

@ -35,34 +35,13 @@ class Doctrine_ORM_Query_AST_IdentificationVariableDeclaration extends Doctrine_
protected $_indexBy = null;
protected $_joinVariableDeclarations = array();
/* Setters */
public function setRangeVariableDeclaration($rangeVariableDeclaration)
{
$this->_rangeVariableDeclaration = $rangeVariableDeclaration;
}
public function setIndexBy($indexBy)
public function __construct($rangeVariableDecl, $indexBy, array $joinVariableDecls)
{
$this->_rangeVariableDeclaration = $rangeVariableDecl;
$this->_indexBy = $indexBy;
$this->_joinVariableDeclarations = $joinVariableDecls;
}
public function addJoinVariableDeclaration($joinVariableDeclaration)
{
$this->_joinVariableDeclarations[] = $joinVariableDeclaration;
}
public function setJoinVariableDeclarations($joinVariableDeclarations, $append = false)
{
$this->_joinVariableDeclarations = ($append === true)
? array_merge($this->_joinVariableDeclarations, $joinVariableDeclarations)
: $joinVariableDeclarations;
}
/* Getters */
public function getRangeVariableDeclaration()

View File

@ -31,14 +31,11 @@
class Doctrine_ORM_Query_AST_IndexBy extends Doctrine_ORM_Query_AST
{
protected $_simpleStateFieldPathExpression = null;
/* Setters */
public function setSimpleStateFieldPathExpression($simpleStateFieldPathExpression)
public function __construct($simpleStateFieldPathExpression)
{
$this->_simpleStateFieldPathExpression = $simpleStateFieldPathExpression;
}
}
/* Getters */
public function getSimpleStateFieldPathExpression()

View File

@ -52,23 +52,15 @@ class Doctrine_ORM_Query_AST_Join extends Doctrine_ORM_Query_AST
protected $_whereType = self::JOIN_WHERE_WITH;
protected $_conditionalExpression = null;
/* Setters */
public function setJoinType($joinType)
public function __construct($joinType, $joinAssocPathExpr, $aliasIdentVar)
{
$this->_joinType = $joinType;
$this->_joinAssociationPathExpression = $joinAssocPathExpr;
$this->_aliasIdentificationVariable = $aliasIdentVar;
}
public function setJoinAssociationPathExpression($joinAssociationPathExpression)
{
$this->_joinAssociationPathExpression = $joinAssociationPathExpression;
}
public function setAliasIdentificationVariable($aliasIdentificationVariable)
{
$this->_aliasIdentificationVariable = $aliasIdentificationVariable;
}
/* Setters */
public function setWhereType($whereType)
{

View File

@ -0,0 +1,33 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of JoinCollectionValuedPathExpression
*
* @author robo
*/
class Doctrine_ORM_Query_AST_JoinPathExpression extends Doctrine_ORM_Query_AST
{
private $_identificationVariable;
private $_assocField;
public function __construct($identificationVariable, $assocField)
{
$this->_identificationVariable = $identificationVariable;
$this->_assocField = $assocField;
}
public function getIdentificationVariable()
{
return $this->_identificationVariable;
}
public function getAssociationField()
{
return $this->_assocField;
}
}

View File

@ -34,19 +34,11 @@ class Doctrine_ORM_Query_AST_JoinVariableDeclaration extends Doctrine_ORM_Query_
protected $_indexBy = null;
/* Setters */
public function setJoin($join)
public function __construct($join, $indexBy)
{
$this->_join = $join;
}
public function setIndexBy($indexBy)
{
$this->_indexBy = $indexBy;
}
/* Getters */
public function getJoin()

View File

@ -0,0 +1,86 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of PathExpression
*
* @author robo
*/
class Doctrine_ORM_Query_AST_PathExpression
{
private $_parts;
// Information that is attached during semantical analysis.
private $_isSimpleStateFieldPathExpression = false;
private $_isSimpleStateFieldAssociationPathExpression = false;
private $_embeddedClassFields = array();
private $_singleValuedAssociationFields = array();
public function __construct(array $parts)
{
$this->_parts = $parts;
}
public function getParts() {
return $this->_parts;
}
/**
* Gets whether the path expression represents a state field that is reached
* either directly (u.name) or by navigating over optionally many embedded class instances
* (u.address.zip).
*
* @return boolean
*/
public function isSimpleStateFieldPathExpression()
{
return $this->_isSimpleStateFieldPathExpression;
}
/**
* Gets whether the path expression represents a state field that is reached
* by navigating over at least one single-valued association and optionally
* many embedded class instances. (u.Group.address.zip, u.Group.address, ...)
*
* @return boolean
*/
public function isSimpleStateFieldAssociationPathExpression()
{
return $this->_isSimpleStateFieldAssociationPathExpression;
}
public function isPartEmbeddedClassField($part)
{
return isset($this->_embeddedClassFields[$part]);
}
public function isPartSingleValuedAssociationField($part)
{
return isset($this->_singleValuedAssociationFields[$part]);
}
/* Setters to attach semantical information during semantical analysis. */
public function setIsSimpleStateFieldPathExpression($bool)
{
$this->_isSimpleStateFieldPathExpression = $bool;
}
public function setIsSimpleStateFieldAssociationPathExpression($bool)
{
$this->_isSimpleStateFieldAssociationPathExpression = $bool;
}
public function setIsEmbeddedClassPart($part)
{
$this->_embeddedClassFields[$part] = true;
}
public function setIsSingleValuedAssociationPart($part)
{
$this->_singleValuedAssociationFields[$part] = true;
}
}

View File

@ -30,23 +30,16 @@
*/
class Doctrine_ORM_Query_AST_RangeVariableDeclaration extends Doctrine_ORM_Query_AST
{
protected $_abstractSchemaName = null;
protected $_aliasIdentificationVariable = null;
/* Setters */
public function setAbstractSchemaName($abstractSchemaName)
{
$this->_abstractSchemaName = $abstractSchemaName;
}
private $_classMetadata;
private $_abstractSchemaName;
private $_aliasIdentificationVariable;
public function setAliasIdentificationVariable($aliasIdentificationVariable)
public function __construct($classMetadata, $aliasIdentificationVar)
{
$this->_aliasIdentificationVariable = $aliasIdentificationVariable;
}
$this->_classMetadata = $classMetadata;
$this->_abstractSchemaName = $classMetadata->getClassName();
$this->_aliasIdentificationVariable = $aliasIdentificationVar;
}
/* Getters */
public function getAbstractSchemaName()
@ -54,11 +47,15 @@ class Doctrine_ORM_Query_AST_RangeVariableDeclaration extends Doctrine_ORM_Query
return $this->_abstractSchemaName;
}
public function getAliasIdentificationVariable()
{
return $this->_aliasIdentificationVariable;
}
public function getClassMetadata()
{
return $this->_classMetadata;
}
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */

View File

@ -33,28 +33,12 @@ class Doctrine_ORM_Query_AST_SelectClause extends Doctrine_ORM_Query_AST
protected $_isDistinct;
protected $_selectExpressions = array();
/* Setters */
public function setIsDistinct($value)
{
$this->_isDistinct = $value;
}
public function addSelectExpression($expression)
{
$this->_selectExpressions[] = $expression;
}
public function setSelectExpressions($expressions, $append = false)
public function __construct(array $selectExpressions, $isDistinct)
{
$this->_selectExpressions = ($append === true)
? array_merge($this->_selectExpressions, $expressions)
: $expressions;
$this->_isDistinct = $isDistinct;
$this->_selectExpressions = $selectExpressions;
}
/* Getters */
public function isDistinct()

View File

@ -34,19 +34,12 @@ class Doctrine_ORM_Query_AST_SelectExpression extends Doctrine_ORM_Query_AST
protected $_expression;
protected $_fieldIdentificationVariable;
/* Setters */
public function setExpression($expression)
public function __construct($expression, $fieldIdentificationVariable)
{
$this->_expression = $expression;
}
public function setFieldIdentificationVariable($fieldIdentificationVariable)
{
$this->_fieldIdentificationVariable = $fieldIdentificationVariable;
}
}
/* Getters */
public function getExpression()

View File

@ -31,54 +31,21 @@
class Doctrine_ORM_Query_AST_SelectStatement extends Doctrine_ORM_Query_AST
{
protected $_selectClause;
protected $_fromClause;
protected $_whereClause;
protected $_groupByClause;
protected $_havingClause;
protected $_orderByClause;
/* Setters */
public function setSelectClause($selectClause)
{
public function __construct($selectClause, $fromClause, $whereClause, $groupByClause,
$havingClause, $orderByClause) {
$this->_selectClause = $selectClause;
}
public function setFromClause($fromClause)
{
$this->_fromClause = $fromClause;
}
public function setWhereClause($whereClause)
{
$this->_whereClause = $whereClause;
}
public function setGroupByClause($groupByClause)
{
$this->_groupByClause = $groupByClause;
}
public function setHavingClause($havingClause)
{
$this->_havingClause = $havingClause;
}
public function setOrderByClause($orderByClause)
{
$this->_orderByClause = $orderByClause;
}
}
/* Getters */
public function getSelectClause()
@ -122,7 +89,7 @@ class Doctrine_ORM_Query_AST_SelectStatement extends Doctrine_ORM_Query_AST
public function buildSql()
{
return $this->_selectClause->buildSql() . ' ' . $this->_fromClause->buildSql()
. (($this->_whereClause !== null) ? ' ' . $this->_whereClause->buildSql() : ' WHERE 1 = 1')
. (($this->_whereClause !== null) ? ' ' . $this->_whereClause->buildSql() : '')
. (($this->_groupByClause !== null) ? ' ' . $this->_groupByClause->buildSql() : '')
. (($this->_havingClause !== null) ? ' ' . $this->_havingClause->buildSql() : '')
. (($this->_orderByClause !== null) ? ' ' . $this->_orderByClause->buildSql() : '');

View File

@ -0,0 +1,16 @@
<?php
/**
* SimpleConditionalExpression ::= ExistsExpression |
* (SimpleStateFieldPathExpression (ComparisonExpression | BetweenExpression | LikeExpression |
* InExpression | NullComparisonExpression)) |
* (CollectionValuedPathExpression EmptyCollectionComparisonExpression) |
* (EntityExpression CollectionMemberExpression)
*
* @author robo
*/
class Doctrine_ORM_Query_AST_SimpleConditionalExpression extends Doctrine_ORM_Query_AST
{
}

View File

@ -33,20 +33,12 @@ class Doctrine_ORM_Query_AST_SimpleStateFieldPathExpression extends Doctrine_ORM
protected $_identificationVariable = null;
protected $_simpleStateField = null;
/* Setters */
public function setIdentificationVariable($identificationVariable)
public function __construct($identificationVariable, $simpleStateField)
{
$this->_identificationVariable = $identificationVariable;
}
public function setSimpleStateField($simpleStateField)
{
$this->_simpleStateField = $simpleStateField;
}
}
/* Getters */
public function getIdentificationVariable()

View File

@ -0,0 +1,26 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of WhereClause
*
* @author robo
*/
class Doctrine_ORM_Query_AST_WhereClause extends Doctrine_ORM_Query_AST
{
private $_conditionalExpression;
public function __construct($conditionalExpression)
{
$this->_conditionalExpression = $conditionalExpression;
}
public function getConditionalExpression()
{
return $this->_conditionalExpression;
}
}

View File

@ -121,7 +121,7 @@ abstract class Doctrine_ORM_Query_AbstractResult
*/
public function getQueryComponent($componentAlias)
{
if ( ! array_key_exists($componentAlias, $this->_queryComponents)) {
if ( ! isset($this->_queryComponents[$componentAlias])) {
throw new Doctrine_ORM_Query_Exception('Unknown query component ' . $componentAlias);
}
@ -188,7 +188,7 @@ abstract class Doctrine_ORM_Query_AbstractResult
/**
* Get component alias associated with given table alias.
* Get DQL alias associated with given SQL table alias.
*
* @param string $tableAlias SQL table alias that identifies the component alias
* @return string Component alias
@ -272,5 +272,4 @@ abstract class Doctrine_ORM_Query_AbstractResult
$this->getEnumParams()
));
}
}

View File

@ -28,7 +28,7 @@
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @link http://www.doctrine-project.org
* @since 2.0
* @version $Revision$
*/
@ -42,13 +42,13 @@ class Doctrine_ORM_Query_Parser
*/
const MIN_ERROR_DISTANCE = 2;
/**
* The Sql Builder object.
* Path expressions that were encountered during parsing of SelectExpressions
* and still need to be validated.
*
* @var Doctrine_ORM_Query_SqlBuilder
* @var array
*/
protected $_sqlbuilder;
private $_pendingPathExpressionsInSelect = array();
/**
* DQL string.
@ -128,7 +128,6 @@ class Doctrine_ORM_Query_Parser
$this->_em = $query->getEntityManager();
$this->_input = $query->getDql();
$this->_scanner = new Doctrine_ORM_Query_Scanner($this->_input);
$this->_sqlBuilder = new Doctrine_ORM_Query_SqlBuilder($this->_em);
$this->_keywordTable = new Doctrine_ORM_Query_Token();
$defaultQueryComponent = Doctrine_ORM_Query_ParserRule::DEFAULT_QUERYCOMPONENT;
@ -231,12 +230,8 @@ class Doctrine_ORM_Query_Parser
*/
public function parse()
{
$this->lookahead = $this->_scanner->next();
// Building the Abstract Syntax Tree
// We have to double the call of QueryLanguage to allow it to work correctly... =\
$DQL = new Doctrine_ORM_Query_Parser_QueryLanguage($this);
$AST = $DQL->parse('QueryLanguage');
// Parse & build AST
$AST = $this->_QueryLanguage();
// Check for end of string
if ($this->lookahead !== null) {
@ -245,27 +240,18 @@ class Doctrine_ORM_Query_Parser
// Check for semantical errors
if (count($this->_errors) > 0) {
throw new Doctrine_ORM_Query_Parser_Exception(implode("\r\n", $this->_errors));
throw new Doctrine_ORM_Query_Exception(implode("\r\n", $this->_errors));
}
// Create SqlWalker who creates the SQL from the AST
$sqlWalker = new Doctrine_ORM_Query_SqlWalker($this->_em, $this->_parserResult);
// Assign the executor in parser result
$this->_parserResult->setSqlExecutor(Doctrine_ORM_Query_SqlExecutor_Abstract::create($AST));
$this->_parserResult->setSqlExecutor(Doctrine_ORM_Query_SqlExecutor_Abstract::create($AST, $sqlWalker));
return $this->_parserResult;
}
/**
* Retrieves the assocated Doctrine_ORM_Query_SqlBuilder to this object.
*
* @return Doctrine_ORM_Query_SqlBuilder
*/
public function getSqlBuilder()
{
return $this->_sqlBuilder;
}
/**
* Returns the scanner object associated with this object.
*
@ -276,7 +262,6 @@ class Doctrine_ORM_Query_Parser
return $this->_scanner;
}
/**
* Returns the parser result associated with this object.
*
@ -287,7 +272,6 @@ class Doctrine_ORM_Query_Parser
return $this->_parserResult;
}
/**
* Generates a new syntax error.
*
@ -315,10 +299,9 @@ class Doctrine_ORM_Query_Parser
$message .= "'{$this->lookahead['value']}'";
}
throw new Doctrine_ORM_Query_Parser_Exception($message);
throw new Doctrine_ORM_Query_Exception($message);
}
/**
* Generates a new semantical error.
*
@ -336,7 +319,6 @@ class Doctrine_ORM_Query_Parser
$this->_logError('Warning: ' . $message, $token);
}
/**
* Logs new error entry.
*
@ -361,8 +343,7 @@ class Doctrine_ORM_Query_Parser
public function getEntityManager()
{
return $this->_em;
}
}
/**
* Retrieve the piece of DQL string given the token position
@ -370,11 +351,677 @@ class Doctrine_ORM_Query_Parser
* @param array $token Token that it was processing.
* @return string Piece of DQL string.
*/
public function getQueryPiece($token, $previousChars = 10, $nextChars = 10)
/*public function getQueryPiece($token, $previousChars = 10, $nextChars = 10)
{
$start = max(0, $token['position'] - $previousChars);
$end = max($token['position'] + $nextChars, strlen($this->_input));
return substr($this->_input, $start, $end);
}*/
private function _isNextToken($token)
{
$la = $this->lookahead;
return ($la['type'] === $token || $la['value'] === $token);
}
/**
* Checks if the next-next (after lookahead) token start a function.
*
* @return boolean
*/
private function _isFunction()
{
$next = $this->_scanner->peek();
$this->_scanner->resetPeek();
return ($next['value'] === '(');
}
/**
* Checks whether the next 2 tokens start a subselect.
*
* @return boolean TRUE if the next 2 tokens start a subselect, FALSE otherwise.
*/
private function _isSubselect()
{
$la = $this->lookahead;
$next = $this->_scanner->peek();
$this->_scanner->resetPeek();
return ($la['value'] === '(' && $next['type'] === Doctrine_ORM_Query_Token::T_SELECT);
}
/* Parse methods */
/**
* QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
*
* @return <type>
*/
private function _QueryLanguage()
{
$this->lookahead = $this->_scanner->next();
switch ($this->lookahead['type']) {
case Doctrine_ORM_Query_Token::T_SELECT:
return $this->_SelectStatement();
break;
case Doctrine_ORM_Query_Token::T_UPDATE:
return $this->_UpdateStatement();
break;
case Doctrine_ORM_Query_Token::T_DELETE:
return $this->_DeleteStatement();
break;
default:
$this->syntaxError('SELECT, UPDATE or DELETE');
break;
}
}
/**
* SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
*
* @return <type>
*/
private function _SelectStatement()
{
$selectClause = $this->_SelectClause();
$fromClause = $this->_FromClause();
$this->_processPendingPathExpressionsInSelect();
$whereClause = $this->_isNextToken(Doctrine_ORM_Query_Token::T_WHERE) ?
$this->_WhereClause() : null;
$groupByClause = $this->_isNextToken(Doctrine_ORM_Query_Token::T_GROUP) ?
$this->_GroupByClause() : null;
$havingClause = $this->_isNextToken(Doctrine_ORM_Query_Token::T_HAVING) ?
$this->_HavingClause() : null;
$orderByClause = $this->_isNextToken(Doctrine_ORM_Query_Token::T_ORDER) ?
$this->_OrderByClause() : null;
return new Doctrine_ORM_Query_AST_SelectStatement(
$selectClause, $fromClause, $whereClause, $groupByClause, $havingClause, $orderByClause
);
}
/**
* Processes pending path expressions that were encountered while parsing
* select expressions. These will be validated to make sure they are indeed
* valid <tt>StateFieldPathExpression</tt>s and additional information
* is attached to their AST nodes.
*/
private function _processPendingPathExpressionsInSelect()
{
$qComps = $this->_parserResult->getQueryComponents();
foreach ($this->_pendingPathExpressionsInSelect as $expr) {
$parts = $expr->getParts();
$numParts = count($parts);
$dqlAlias = $parts[0];
if (count($parts) == 2) {
$expr->setIsSimpleStateFieldPathExpression(true);
if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[1])) {
$this->syntaxError();
}
} else {
$embeddedClassFieldSeen = false;
$assocSeen = false;
for ($i = 1; $i < $numParts - 1; ++$i) {
if ($qComps[$dqlAlias]['metadata']->hasAssociation($parts[$i])) {
if ($embeddedClassFieldSeen) {
$this->semanticalError('Invalid navigation path.');
}
// Indirect join
$assoc = $qComps[$dqlAlias]['metadata']->getAssociationMapping($parts[$i]);
if ( ! $assoc->isOneToOne()) {
$this->semanticalError('Single-valued association expected.');
}
$expr->setIsSingleValuedAssociationPart($parts[$i]);
//TODO...
$assocSeen = true;
} else if ($qComps[$dqlAlias]['metadata']->hasEmbeddedClassField($parts[$i])) {
//TODO...
$expr->setIsEmbeddedClassPart($parts[$i]);
$this->syntaxError();
} else {
$this->syntaxError();
}
}
if ( ! $assocSeen) {
$expr->setIsSimpleStateFieldPathExpression(true);
} else {
$expr->setIsSimpleStateFieldAssociationPathExpression(true);
}
// Last part MUST be a simple state field
if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[$numParts-1])) {
$this->syntaxError();
}
}
}
}
private function _UpdateStatement()
{
//TODO
}
private function _DeleteStatement()
{
//TODO
}
/**
* SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
*/
private function _SelectClause()
{
$isDistinct = false;
$this->match(Doctrine_ORM_Query_Token::T_SELECT);
// Inspecting if we are in a DISTINCT query
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_DISTINCT)) {
$this->match(Doctrine_ORM_Query_Token::T_DISTINCT);
$isDistinct = true;
}
// Process SelectExpressions (1..N)
$selectExpressions = array();
$selectExpressions[] = $this->_SelectExpression();
while ($this->_isNextToken(',')) {
$this->match(',');
$selectExpressions[] = $this->_SelectExpression();
}
return new Doctrine_ORM_Query_AST_SelectClause($selectExpressions, $isDistinct);
}
/**
* FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}
*/
private function _FromClause()
{
$this->match(Doctrine_ORM_Query_Token::T_FROM);
$identificationVariableDeclarations = array();
$identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration();
while ($this->_isNextToken(',')) {
$this->match(',');
$identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration();
}
return new Doctrine_ORM_Query_AST_FromClause($identificationVariableDeclarations);
}
/**
* SelectExpression ::=
* IdentificationVariable | StateFieldPathExpression |
* (AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable]
*/
private function _SelectExpression()
{
$expression = null;
$fieldIdentificationVariable = null;
$peek = $this->_scanner->peek();
$this->_scanner->resetPeek();
// First we recognize for an IdentificationVariable (DQL class alias)
if ($peek['value'] != '.' && $this->lookahead['type'] === Doctrine_ORM_Query_Token::T_IDENTIFIER) {
$expression = $this->_IdentificationVariable();
} else if (($isFunction = $this->_isFunction()) !== false || $this->_isSubselect()) {
$expression = $isFunction ? $this->_AggregateExpression() : $this->_Subselect();
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_AS)) {
$this->match(Doctrine_ORM_Query_Token::T_AS);
$fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable();
} elseif ($this->_isNextToken(Doctrine_ORM_Query_Token::T_IDENTIFIER)) {
$fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable();
}
} else {
$expression = $this->_PathExpressionInSelect();
}
return new Doctrine_ORM_Query_AST_SelectExpression($expression, $fieldIdentificationVariable);
}
/**
* IdentificationVariable ::= identifier
*/
private function _IdentificationVariable()
{
$this->match(Doctrine_ORM_Query_Token::T_IDENTIFIER);
return $this->token['value'];
}
/**
* IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
*/
private function _IdentificationVariableDeclaration()
{
$rangeVariableDeclaration = $this->_RangeVariableDeclaration();
$indexBy = $this->_isNextToken(Doctrine_ORM_Query_Token::T_INDEX) ?
$this->_IndexBy() : null;
$joinVariableDeclarations = array();
while (
$this->_isNextToken(Doctrine_ORM_Query_Token::T_LEFT) ||
$this->_isNextToken(Doctrine_ORM_Query_Token::T_INNER) ||
$this->_isNextToken(Doctrine_ORM_Query_Token::T_JOIN)
) {
$joinVariableDeclarations[] = $this->_JoinVariableDeclaration();
}
return new Doctrine_ORM_Query_AST_IdentificationVariableDeclaration(
$rangeVariableDeclaration, $indexBy, $joinVariableDeclarations
);
}
/**
* RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
*/
private function _RangeVariableDeclaration()
{
$abstractSchemaName = $this->_AbstractSchemaName();
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_AS)) {
$this->match(Doctrine_ORM_Query_Token::T_AS);
}
$aliasIdentificationVariable = $this->_AliasIdentificationVariable();
$classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
// Building queryComponent
$queryComponent = array(
'metadata' => $classMetadata,
'parent' => null,
'relation' => null,
'map' => null,
'scalar' => null,
);
$this->_parserResult->setQueryComponent($aliasIdentificationVariable, $queryComponent);
return new Doctrine_ORM_Query_AST_RangeVariableDeclaration(
$classMetadata, $aliasIdentificationVariable
);
}
/**
* AbstractSchemaName ::= identifier
*/
private function _AbstractSchemaName()
{
$this->match(Doctrine_ORM_Query_Token::T_IDENTIFIER);
return $this->token['value'];
}
/**
* AliasIdentificationVariable = identifier
*/
private function _AliasIdentificationVariable()
{
$this->match(Doctrine_ORM_Query_Token::T_IDENTIFIER);
return $this->token['value'];
}
/**
* Special rule that acceps all kinds of path expressions.
*/
private function _PathExpression()
{
$this->match(Doctrine_ORM_Query_Token::T_IDENTIFIER);
$parts = array($this->token['value']);
while ($this->_isNextToken('.')) {
$this->match('.');
$this->match(Doctrine_ORM_Query_Token::T_IDENTIFIER);
$parts[] = $this->token['value'];
}
$pathExpression = new Doctrine_ORM_Query_AST_PathExpression($parts);
return $pathExpression;
}
/**
* Special rule that acceps all kinds of path expressions. and defers their
* semantical checking until the FROM part has been parsed completely (joins inclusive).
* Mainly used for path expressions in the SelectExpressions.
*/
private function _PathExpressionInSelect()
{
$expr = $this->_PathExpression();
$this->_pendingPathExpressionsInSelect[] = $expr;
return $expr;
}
/**
* JoinVariableDeclaration ::= Join [IndexBy]
*/
private function _JoinVariableDeclaration()
{
$join = $this->_Join();
$indexBy = $this->_isNextToken(Doctrine_ORM_Query_Token::T_INDEX) ?
$this->_IndexBy() : null;
return new Doctrine_ORM_Query_AST_JoinVariableDeclaration($join, $indexBy);
}
/**
* Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
* ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression]
*/
private function _Join()
{
// Check Join type
$joinType = Doctrine_ORM_Query_AST_Join::JOIN_TYPE_INNER;
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_LEFT)) {
$this->match(Doctrine_ORM_Query_Token::T_LEFT);
// Possible LEFT OUTER join
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_OUTER)) {
$this->match(Doctrine_ORM_Query_Token::T_OUTER);
$joinType = Doctrine_ORM_Query_AST_Join::JOIN_TYPE_LEFTOUTER;
} else {
$joinType = Doctrine_ORM_Query_AST_Join::JOIN_TYPE_LEFT;
}
} else if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_INNER)) {
$this->match(Doctrine_ORM_Query_Token::T_INNER);
}
$this->match(Doctrine_ORM_Query_Token::T_JOIN);
$joinPathExpression = $this->_JoinPathExpression();
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_AS)) {
$this->match(Doctrine_ORM_Query_Token::T_AS);
}
$aliasIdentificationVariable = $this->_AliasIdentificationVariable();
// Verify that the association exists, if yes update the ParserResult
// with the new component.
$parentComp = $this->_parserResult->getQueryComponent($joinPathExpression->getIdentificationVariable());
$parentClass = $parentComp['metadata'];
$assocField = $joinPathExpression->getAssociationField();
if ( ! $parentClass->hasAssociation($assocField)) {
$this->semanticalError("Class " . $parentClass->getClassName() .
" has no association named '$assocField'.");
}
$targetClassName = $parentClass->getAssociationMapping($assocField)->getTargetEntityName();
// Building queryComponent
$joinQueryComponent = array(
'metadata' => $this->_em->getClassMetadata($targetClassName),
'parent' => $joinPathExpression->getIdentificationVariable(),
'relation' => $parentClass->getAssociationMapping($assocField),
'map' => null,
'scalar' => null,
);
$this->_parserResult->setQueryComponent($aliasIdentificationVariable, $joinQueryComponent);
// Create AST node
$join = new Doctrine_ORM_Query_AST_Join($joinType, $joinPathExpression, $aliasIdentificationVariable);
// Check Join where type
if (
$this->_isNextToken(Doctrine_ORM_Query_Token::T_ON) ||
$this->_isNextToken(Doctrine_ORM_Query_Token::T_WITH)
) {
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_ON)) {
$this->match(Doctrine_ORM_Query_Token::T_ON);
$join->setWhereType(Doctrine_ORM_Query_AST_Join::JOIN_WHERE_ON);
} else {
$this->match(Doctrine_ORM_Query_Token::T_WITH);
}
$join->setConditionalExpression($this->_ConditionalExpression());
}
return $join;
}
/*private function _JoinAssociationPathExpression() {
if ($this->_isSingleValuedPathExpression()) {
return $this->_JoinSingleValuedAssociationPathExpression();
} else {
return $this->_JoinCollectionValuedPathExpression();
}
}*/
/*private function _isSingleValuedPathExpression()
{
$parserResult = $this->_parserResult;
// Trying to recoginize this grammar:
// IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)
$token = $this->lookahead;
$this->_scanner->resetPeek();
if ($parserResult->hasQueryComponent($token['value'])) {
$queryComponent = $parserResult->getQueryComponent($token['value']);
$peek = $this->_scanner->peek();
if ($peek['value'] === '.') {
$peek2 = $this->_scanner->peek();
if ($queryComponent['metadata']->hasAssociation($peek2['value']) &&
$queryComponent['metadata']->getAssociationMapping($peek2['value'])->isOneToOne()) {
return true;
}
}
}
return false;
}*/
/**
* JoinPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)
*/
private function _JoinPathExpression()
{
$identificationVariable = $this->_IdentificationVariable();
$this->match('.');
$this->match(Doctrine_ORM_Query_Token::T_IDENTIFIER);
$assocField = $this->token['value'];
return new Doctrine_ORM_Query_AST_JoinPathExpression(
$identificationVariable, $assocField
);
}
/**
* IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression
*/
private function _IndexBy()
{
$this->match(Doctrine_ORM_Query_Token::T_INDEX);
$this->match(Doctrine_ORM_Query_Token::T_BY);
$pathExp = $this->_SimpleStateFieldPathExpression();
// Add the INDEX BY info to the query component
$qComp = $this->_parserResult->getQueryComponent($pathExp->getIdentificationVariable());
$qComp['map'] = $pathExp->getSimpleStateField();
$this->_parserResult->setQueryComponent($pathExp->getIdentificationVariable(), $qComp);
return $pathExp;
}
/**
* SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
*/
private function _SimpleStateFieldPathExpression()
{
$identificationVariable = $this->_IdentificationVariable();
$this->match('.');
$this->match(Doctrine_ORM_Query_Token::T_IDENTIFIER);
$simpleStateField = $this->token['value'];
return new Doctrine_ORM_Query_AST_SimpleStateFieldPathExpression($identificationVariable, $simpleStateField);
}
/**
* AggregateExpression ::=
* ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
* "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")"
*/
private function _AggregateExpression()
{
$isDistinct = false;
$functionName = '';
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_COUNT)) {
$this->match(Doctrine_ORM_Query_Token::T_COUNT);
$functionName = $this->token['value'];
$this->match('(');
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_DISTINCT)) {
$this->match(Doctrine_ORM_Query_Token::T_DISTINCT);
$isDistinct = true;
}
// For now we only support a PathExpression here...
$pathExp = $this->_PathExpression();
$this->match(')');
} else if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_AVG)) {
$this->match(Doctrine_ORM_Query_Token::T_AVG);
$functionName = $this->token['value'];
$this->match('(');
//...
} else {
$this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
}
return new Doctrine_ORM_Query_AST_AggregateExpression($functionName, $pathExp, $isDistinct);
}
/**
* GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
* GroupByItem ::= SingleValuedPathExpression
*/
private function _GroupByClause()
{
$this->match(Doctrine_ORM_Query_Token::T_GROUP);
$this->match(Doctrine_ORM_Query_Token::T_BY);
$groupByItems = array();
$groupByItems[] = $this->_PathExpression();
while ($this->_isNextToken(',')) {
$this->match(',');
$groupByItems[] = $this->_PathExpression();
}
return new Doctrine_ORM_Query_AST_GroupByClause($groupByItems);
}
/**
* WhereClause ::= "WHERE" ConditionalExpression
*/
private function _WhereClause()
{
$this->match(Doctrine_ORM_Query_Token::T_WHERE);
return new Doctrine_ORM_Query_AST_WhereClause($this->_ConditionalExpression());
}
/**
* ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
*/
private function _ConditionalExpression()
{
$conditionalTerms = array();
$conditionalTerms[] = $this->_ConditionalTerm();
while ($this->_isNextToken(Doctrine_ORM_Query_Token::T_OR)) {
$this->match(Doctrine_ORM_Query_Token::T_OR);
$conditionalTerms[] = $this->_ConditionalTerm();
}
return new Doctrine_ORM_Query_AST_ConditionalExpression($conditionalTerms);
}
/**
* ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
*/
private function _ConditionalTerm()
{
$conditionalFactors = array();
$conditionalFactors[] = $this->_ConditionalFactor();
while ($this->_isNextToken(Doctrine_ORM_Query_Token::T_AND)) {
$this->match(Doctrine_ORM_Query_Token::T_AND);
$conditionalFactors[] = $this->_ConditionalFactor();
}
return new Doctrine_ORM_Query_AST_ConditionalTerm($conditionalFactors);
}
/**
* ConditionalFactor ::= ["NOT"] ConditionalPrimary
*/
private function _ConditionalFactor()
{
$not = false;
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_NOT)) {
$this->match(Doctrine_ORM_Query_Token::T_NOT);
$not = true;
}
return new Doctrine_ORM_Query_AST_ConditionalFactor($this->_ConditionalPrimary(), $not);
}
/**
* ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
*/
private function _ConditionalPrimary()
{
$condPrimary = new Doctrine_ORM_Query_AST_ConditionalPrimary;
if ($this->_isNextToken('(')) {
$this->match('(');
$conditionalExpression = $this->_ConditionalExpression();
$this->match(')');
$condPrimary->setConditionalExpression($conditionalExpression);
} else {
$condPrimary->setSimpleConditionalExpression($this->_SimpleConditionalExpression());
}
return $condPrimary;
}
/**
* SimpleConditionalExpression ::= ExistsExpression |
* (SimpleStateFieldPathExpression (ComparisonExpression | BetweenExpression | LikeExpression |
* InExpression | NullComparisonExpression)) |
* (CollectionValuedPathExpression EmptyCollectionComparisonExpression) |
* (EntityExpression CollectionMemberExpression)
*/
private function _SimpleConditionalExpression()
{
if ($this->_getExpressionType() === Doctrine_ORM_Query_Token::T_EXISTS) {
return $this->_ExistsExpression();
}
// For now... just SimpleStateFieldPathExpression
$leftExpression = $this->_SimpleStateFieldPathExpression();
switch ($this->_getExpressionType()) {
case Doctrine_ORM_Query_Token::T_NONE:
// [TODO] Check out ticket #935 to understand what will be done with enumParams
$rightExpression = $this->_ComparisonExpression();
break;
case Doctrine_ORM_Query_Token::T_BETWEEN:
$rightExpression = $this->_BetweenExpression();
break;
case Doctrine_ORM_Query_Token::T_LIKE:
$rightExpression = $this->_LikeExpression();
break;
case Doctrine_ORM_Query_Token::T_IN:
$rightExpression = $this->_InExpression();
break;
case Doctrine_ORM_Query_Token::T_IS:
$rightExpression = $this->_NullComparisonExpression();
break;
case Doctrine_ORM_Query_Token::T_ALL:
case Doctrine_ORM_Query_Token::T_ANY:
case Doctrine_ORM_Query_Token::T_SOME:
$rightExpression = $this->_QuantifiedExpression();
break;
default:
$message = "BETWEEN, LIKE, IN, IS, quantified (ALL, ANY or SOME) "
. "or comparison (=, <, <=, <>, >, >=, !=)";
$this->syntaxError($message);
break;
}
}
private function _getExpressionType()
{
if ($this->_isNextToken(Doctrine_ORM_Query_Token::T_NOT)) {
$token = $this->_scanner->peek();
$this->_scanner->resetPeek();
} else {
$token = $this->lookahead;
}
return $token['type'];
}
private function _ComparisonExpression()
{
var_dump($this->lookahead);
}
}

View File

@ -91,14 +91,7 @@ class Doctrine_ORM_Query_Parser_SelectExpression extends Doctrine_ORM_Query_Pars
// We have an identifier here
if ($token['type'] === Doctrine_ORM_Query_Token::T_IDENTIFIER) {
$token = $this->_parser->getScanner()->peek();
// If we have a dot ".", then next char must be the "*"
if ($token['type'] === Doctrine_ORM_Query_Token::T_DOT) {
$token = $this->_parser->getScanner()->peek();
return $token['value'] === '*';
}
return true;
}
return false;

View File

@ -44,9 +44,9 @@ class Doctrine_ORM_Query_Parser_SelectStatement extends Doctrine_ORM_Query_Parse
// Disable the semantical check for SelectClause now. This is needed
// since we dont know the query components yet (will be known only
// when the FROM and WHERE clause are processed).
$this->_dataHolder->set('semanticalCheck', false);
//$this->_dataHolder->set('semanticalCheck', false);
$this->_selectClause = $this->parse('SelectClause');
$this->_dataHolder->remove('semanticalCheck');
//$this->_dataHolder->remove('semanticalCheck');
$this->_AST->setFromClause($this->parse('FromClause'));

View File

@ -38,14 +38,6 @@ class Doctrine_ORM_Query_ParserResult extends Doctrine_ORM_Query_AbstractResult
*/
protected $_em;
/**
* A simple array keys representing table aliases and values table alias
* seeds. The seeds are used for generating short table aliases.
*
* @var array $_tableAliasSeeds
*/
protected $_tableAliasSeeds = array();
/**
* Simple array of keys representing the fields used in query.
*
@ -154,33 +146,4 @@ class Doctrine_ORM_Query_ParserResult extends Doctrine_ORM_Query_AbstractResult
{
return isset($this->_queryFields[$fieldAlias]);
}
/**
* Generates a table alias from given table name and associates
* it with given component alias
*
* @param string $componentName Component name to be associated with generated table alias
* @return string Generated table alias
*/
public function generateTableAlias($componentName)
{
$baseAlias = strtolower(preg_replace('/[^A-Z]/', '\\1', $componentName));
// We may have a situation where we have all chars are lowercased
if ( $baseAlias == '' ) {
// We simply grab the first 2 chars of component name
$baseAlias = substr($componentNam, 0, 2);
}
$alias = $baseAlias;
if ( ! isset($this->_tableAliasSeeds[$baseAlias])) {
$this->_tableAliasSeeds[$baseAlias] = 1;
} else {
$alias .= $this->_tableAliasSeeds[$baseAlias]++;
}
return $alias;
}
}

View File

@ -107,40 +107,35 @@ abstract class Doctrine_ORM_Query_ParserRule
*
* @param string $RuleName BNF Grammar Rule name
* @param array $paramHolder Production parameter holder
* @return Doctrine_ORM_Query_ParserRule
* @return Doctrine_ORM_Query_AST The constructed subtree during parsing.
*/
public function parse($RuleName)
public function parse($ruleName)
{
$BNFGrammarRule = $this->_getGrammarRule($RuleName);
//echo "Processing class: " . get_class($BNFGrammarRule) . "...\n";
//echo "Params: " . var_export($paramHolder, true) . "\n";
echo $ruleName . PHP_EOL;
return $this->_getGrammarRule($ruleName)->syntax();
// Syntax check
if ( ! $this->_dataHolder->has('syntaxCheck') || $this->_dataHolder->get('syntaxCheck') === true) {
/*if ( ! $this->_dataHolder->has('syntaxCheck') || $this->_dataHolder->get('syntaxCheck') === true) {
//echo "Processing syntax checks of " . $RuleName . "...\n";
$return = $BNFGrammarRule->syntax();
if ($return !== null) {
//echo "Returning Gramma Rule class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
return $return;
$ASTNode = $BNFGrammarRule->syntax();
if ($ASTNode !== null) {
//echo "Returning Grammar Rule class: " . (is_object($ASTNode) ? get_class($ASTNode) : $ASTNode) . "...\n";
return $ASTNode;
}
}
}*/
// Semantical check
if ( ! $this->_dataHolder->has('semanticalCheck') || $this->_dataHolder->get('semanticalCheck') === true) {
//echo "Processing semantical checks of " . $RuleName . "...\n";
/*if ( ! $this->_dataHolder->has('semanticalCheck') || $this->_dataHolder->get('semanticalCheck') === true) {
echo "Processing semantical checks of " . $RuleName . "...\n";
$return = $BNFGrammarRule->semantical();
if ($return !== null) {
//echo "Returning Gramma Rule class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
echo "Returning Grammar Rule class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
return $return;
}
}
}*/
return $BNFGrammarRule;
}
@ -178,15 +173,6 @@ abstract class Doctrine_ORM_Query_ParserRule
public function AST($AstName)
{
$class = 'Doctrine_ORM_Query_AST_' . $AstName;
//echo $class . "\r\n";
if ( ! class_exists($class)) {
throw new Doctrine_ORM_Query_Parser_Exception(
"Unknown AST node '" . $AstName . "'. Could not find related compiler class."
);
}
return new $class($this->_parser->getParserResult());
}

View File

@ -1,65 +0,0 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
/**
* The SqlBuilder. Creates SQL out of an AST.
*
* INTERNAL: For platform-specific SQL, the platform of the connection should be used.
* ($this->_connection->getDatabasePlatform())
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_ORM_Query_SqlBuilder
{
protected $_em;
protected $_conn;
public function __construct(Doctrine_ORM_EntityManager $em)
{
$this->_em = $em;
$this->_conn = $this->_em->getConnection();
}
/**
* Retrieves the assocated Doctrine_Connection to this object.
*
* @return Doctrine_Connection
*/
public function getConnection()
{
return $this->_connection;
}
/**
* @nodoc
*/
public function quoteIdentifier($identifier)
{
return $this->_conn->quoteIdentifier($identifier);
}
}

View File

@ -1,36 +0,0 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
/**
* MySql class of Sql Builder object
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 1.0
* @version $Revision$
*/
class Doctrine_ORM_Query_SqlBuilder_Mysql extends Doctrine_ORM_Query_SqlBuilder
{
}

View File

@ -1,36 +0,0 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
/**
* Sqlite class of Sql Builder object
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 1.0
* @version $Revision$
*/
class Doctrine_ORM_Query_SqlBuilder_Sqlite extends Doctrine_ORM_Query_SqlBuilder
{
}

View File

@ -30,15 +30,10 @@
*/
abstract class Doctrine_ORM_Query_SqlExecutor_Abstract implements Serializable
{
// [TODO] Remove me later!
//public $AST;
protected $_sqlStatements;
public function __construct(Doctrine_ORM_Query_AST $AST)
public function __construct(Doctrine_ORM_Query_AST $AST, $sqlWalker)
{
// [TODO] Remove me later!
//$this->AST = $AST;
}
/**
@ -66,7 +61,7 @@ abstract class Doctrine_ORM_Query_SqlExecutor_Abstract implements Serializable
* @param Doctrine_ORM_Query_AST $AST The root node of the AST.
* @return Doctrine_ORM_Query_SqlExecutor_Abstract The executor that is suitable for the given AST.
*/
public static function create(Doctrine_ORM_Query_AST $AST)
public static function create(Doctrine_ORM_Query_AST $AST, $sqlWalker)
{
$isDeleteStatement = $AST instanceof Doctrine_ORM_Query_AST_DeleteStatement;
$isUpdateStatement = $AST instanceof Doctrine_ORM_Query_AST_UpdateStatement;
@ -84,7 +79,7 @@ abstract class Doctrine_ORM_Query_SqlExecutor_Abstract implements Serializable
*/
return new Doctrine_ORM_Query_SqlExecutor_SingleTableDeleteUpdate($AST);
} else {
return new Doctrine_ORM_Query_SqlExecutor_SingleSelect($AST);
return new Doctrine_ORM_Query_SqlExecutor_SingleSelect($AST, $sqlWalker);
}
}

View File

@ -30,10 +30,10 @@
*/
class Doctrine_ORM_Query_SqlExecutor_SingleSelect extends Doctrine_ORM_Query_SqlExecutor_Abstract
{
public function __construct(Doctrine_ORM_Query_AST $AST)
public function __construct(Doctrine_ORM_Query_AST_SelectStatement $AST, $sqlWalker)
{
parent::__construct($AST);
$this->_sqlStatements = $AST->buildSql();
parent::__construct($AST, $sqlWalker);
$this->_sqlStatements = $sqlWalker->walkSelectStatement($AST);
}
public function execute(Doctrine_DBAL_Connection $conn, array $params)

View File

@ -0,0 +1,254 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of SqlWalker
*
* @author robo
*/
class Doctrine_ORM_Query_SqlWalker
{
/**
* A simple array keys representing table aliases and values table alias
* seeds. The seeds are used for generating short SQL table aliases.
*
* @var array $_tableAliasSeeds
*/
private $_tableAliasSeeds = array();
private $_parserResult;
private $_em;
private $_dqlToSqlAliasMap = array();
private $_scalarAliasCounter = 0;
public function __construct($em, $parserResult)
{
$this->_em = $em;
$this->_parserResult = $parserResult;
$sqlToDqlAliasMap = array();
foreach ($parserResult->getQueryComponents() as $dqlAlias => $qComp) {
if ($dqlAlias != 'dctrn') {
$sqlAlias = $this->generateTableAlias($qComp['metadata']->getClassName());
$sqlToDqlAliasMap[$sqlAlias] = $dqlAlias;
}
}
// SQL => DQL alias stored in ParserResult, needed for hydration.
$parserResult->setTableAliasMap($sqlToDqlAliasMap);
// DQL => SQL alias stored only locally, needed for SQL construction.
$this->_dqlToSqlAliasMap = array_flip($sqlToDqlAliasMap);
}
public function walkSelectStatement(Doctrine_ORM_Query_AST_SelectStatement $AST)
{
$sql = $this->walkSelectClause($AST->getSelectClause());
$sql .= $this->walkFromClause($AST->getFromClause());
$sql .= $AST->getGroupByClause() ? $this->walkGroupByClause($AST->getGroupByClause()) : '';
//... more clauses
return $sql;
}
public function walkSelectClause($selectClause)
{
return 'SELECT ' . (($selectClause->isDistinct()) ? 'DISTINCT ' : '')
. implode(', ', array_map(array(&$this, 'walkSelectExpression'),
$selectClause->getSelectExpressions()));
}
public function walkFromClause($fromClause)
{
$sql = ' FROM ';
$identificationVarDecls = $fromClause->getIdentificationVariableDeclarations();
$firstIdentificationVarDecl = $identificationVarDecls[0];
$rangeDecl = $firstIdentificationVarDecl->getRangeVariableDeclaration();
$sql .= $rangeDecl->getClassMetadata()->getTableName() . ' '
. $this->_dqlToSqlAliasMap[$rangeDecl->getAliasIdentificationVariable()];
foreach ($firstIdentificationVarDecl->getJoinVariableDeclarations() as $joinVarDecl) {
$sql .= $this->walkJoinVariableDeclaration($joinVarDecl);
}
return $sql;
}
/**
* Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
*
* @param JoinVariableDeclaration $joinVarDecl
* @return string
*/
public function walkJoinVariableDeclaration($joinVarDecl)
{
$join = $joinVarDecl->getJoin();
$joinType = $join->getJoinType();
if ($joinType == Doctrine_ORM_Query_AST_Join::JOIN_TYPE_LEFT ||
$joinType == Doctrine_ORM_Query_AST_Join::JOIN_TYPE_LEFTOUTER) {
$sql = ' LEFT JOIN ';
} else {
$sql = ' INNER JOIN ';
}
$joinAssocPathExpr = $join->getJoinAssociationPathExpression();
$sourceQComp = $this->_parserResult->getQueryComponent($joinAssocPathExpr->getIdentificationVariable());
$targetQComp = $this->_parserResult->getQueryComponent($join->getAliasIdentificationVariable());
$targetTableName = $targetQComp['metadata']->getTableName();
$targetTableAlias = $this->_dqlToSqlAliasMap[$join->getAliasIdentificationVariable()];
$sourceTableAlias = $this->_dqlToSqlAliasMap[$joinAssocPathExpr->getIdentificationVariable()];
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
if ( ! $targetQComp['relation']->isOwningSide()) {
$assoc = $targetQComp['metadata']->getAssociationMapping($targetQComp['relation']->getMappedByFieldName());
} else {
$assoc = $targetQComp['relation'];
}
if ($targetQComp['relation']->isOneToOne() || $targetQComp['relation']->isOneToMany()) {
$joinColumns = $assoc->getSourceToTargetKeyColumns();
$first = true;
foreach ($joinColumns as $sourceColumn => $targetColumn) {
if ( ! $first) $sql .= ' AND ';
if ($targetQComp['relation']->isOwningSide()) {
$sql .= "$sourceTableAlias.$sourceColumn = $targetTableAlias.$targetColumn";
} else {
$sql .= "$sourceTableAlias.$targetColumn = $targetTableAlias.$sourceColumn";
}
}
} else { // ManyToMany
//TODO
}
return $sql;
}
/**
* Walks down a SelectExpression AST node and generates the corresponding SQL.
*
* @param <type> $selectExpression
* @return string
*/
public function walkSelectExpression($selectExpression)
{
$sql = '';
if ($selectExpression->getExpression() instanceof Doctrine_ORM_Query_AST_PathExpression) {
$pathExpression = $selectExpression->getExpression();
if ($pathExpression->isSimpleStateFieldPathExpression()) {
$parts = $pathExpression->getParts();
$numParts = count($parts);
$dqlAlias = $parts[0];
$fieldName = $parts[$numParts-1];
$qComp = $this->_parserResult->getQueryComponent($dqlAlias);
$class = $qComp['metadata'];
if ($numParts > 2) {
for ($i = 1; $i < $numParts-1; ++$i) {
//TODO
}
}
$sqlTableAlias = $this->_dqlToSqlAliasMap[$dqlAlias];
$sql .= $sqlTableAlias . '.' . $class->getColumnName($fieldName) .
' AS ' . $sqlTableAlias . '__' . $class->getColumnName($fieldName);
} else if ($pathExpression->isSimpleStateFieldAssociationPathExpression()) {
echo "HERE!!";
} else {
throw new Doctrine_ORM_Query_Exception("Encountered invalid PathExpression during SQL construction.");
}
}
else if ($selectExpression->getExpression() instanceof Doctrine_ORM_Query_AST_AggregateExpression) {
$aggExpr = $selectExpression->getExpression();
if ( ! $selectExpression->getFieldIdentificationVariable()) {
$alias = $this->_scalarAliasCounter++;
} else {
$alias = $selectExpression->getFieldIdentificationVariable();
}
$parts = $aggExpr->getPathExpression()->getParts();
$dqlAlias = $parts[0];
$fieldName = $parts[1];
$qComp = $this->_parserResult->getQueryComponent($dqlAlias);
$columnName = $qComp['metadata']->getColumnName($fieldName);
$sql .= $aggExpr->getFunctionName() . '(';
$sql .= $this->_dqlToSqlAliasMap[$dqlAlias] . '.' . $columnName;
$sql .= ') AS dctrn__' . $alias;
}
//TODO: else if Subselect
else {
$dqlAlias = $selectExpression->getExpression();
$queryComp = $this->_parserResult->getQueryComponent($dqlAlias);
$class = $queryComp['metadata'];
$sqlTableAlias = $this->_dqlToSqlAliasMap[$dqlAlias];
$beginning = true;
foreach ($class->getFieldMappings() as $fieldName => $fieldMapping) {
if ($beginning) {
$beginning = false;
} else {
$sql .= ', ';
}
$sql .= $sqlTableAlias . '.' . $fieldMapping['columnName'] .
' AS ' . $sqlTableAlias . '__' . $fieldMapping['columnName'];
}
}
return $sql;
}
public function walkGroupByClause($groupByClause)
{
return ' GROUP BY '
. implode(', ', array_map(array(&$this, 'walkGroupByItem'),
$groupByClause->getGroupByItems()));
}
public function walkGroupByItem($pathExpr)
{
//TODO: support general SingleValuedPathExpression, not just state field
$parts = $pathExpr->getParts();
$qComp = $this->_parserResult->getQueryComponent($parts[0]);
$columnName = $qComp['metadata']->getColumnName($parts[1]);
return $this->_dqlToSqlAliasMap[$parts[0]] . '.' . $columnName;
}
public function walkUpdateStatement(Doctrine_ORM_Query_AST_UpdateStatement $AST)
{
}
public function walkDeleteStatement(Doctrine_ORM_Query_AST_DeleteStatement $AST)
{
}
/**
* Generates an SQL table alias from given table name and associates
* it with given component alias
*
* @param string $componentName Component name to be associated with generated table alias
* @return string Generated table alias
*/
public function generateTableAlias($componentName)
{
$baseAlias = strtolower(preg_replace('/[^A-Z]/', '\\1', $componentName));
// We may have a situation where we have all chars are lowercased
if ($baseAlias == '') {
// We simply grab the first 2 chars of component name
$baseAlias = substr($componentNam, 0, 2);
}
$alias = $baseAlias;
if ( ! isset($this->_tableAliasSeeds[$baseAlias])) {
$this->_tableAliasSeeds[$baseAlias] = 1;
} else {
$alias .= $this->_tableAliasSeeds[$baseAlias]++;
}
return $alias;
}
}

View File

@ -54,7 +54,7 @@ AliasIdentificationVariable :: = identifier
/* identifier that must be a class name (the "User" of "FROM User u") */
AbstractSchemaName ::= identifier
/* identifier that must be a field (the "name" of "u.name") */
/* identifier that must be a field (the "name" of "u.name") */
/* This is responsable to know if the field exists in Object, no matter if it's a relation or a simple field */
FieldIdentificationVariable ::= identifier
@ -67,49 +67,49 @@ SingleValuedAssociationField ::= FieldIdentificationVariable
/* identifier that must be an embedded class state field (for the future) */
EmbeddedClassStateField ::= FieldIdentificationVariable
/* identifier that must be a simple state field (name, email, ...) (the "name" of "u.name") */
/* identifier that must be a simple state field (name, email, ...) (the "name" of "u.name") */
/* The difference between this and FieldIdentificationVariable is only semantical, because it points to a single field (not mapping to a relation) */
SimpleStateField ::= FieldIdentificationVariable
/* identifier that must be unique among other mapped field aliases (the "total" of "COUNT(*) AS total")*/
/* identifier that must be unique among other mapped field aliases (the "total" of "COUNT(*) AS total")*/
FieldAliasIdentificationVariable = identifier
/*
* PATH EXPRESSIONS
*/
*/
/* "u.Group" or "u.Phonenumbers" declarations */
JoinAssociationPathExpression ::= JoinCollectionValuedPathExpression | JoinSingleValuedAssociationPathExpression
/* "u.Phonenumbers" */
/* "u.Phonenumbers" */
JoinCollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
/* "u.Group" */
JoinSingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
/* "u.Group" or "u.Phonenumbers" usages */
AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
/* "u.name" or "u.Group" */
SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
/* "u.name" or "u.Group.name" */
StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression
/* "u.Group" */
SingleValuedAssociationPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* SingleValuedAssociationField
JoinSingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
/* "u.Group" or "u.Phonenumbers" usages */
AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
/* "u.name" or "u.Group" */
SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
/* "u.name" or "u.Group.name" */
StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression
/* "u.Group" */
SingleValuedAssociationPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* SingleValuedAssociationField
/* "u.Group.Permissions" */
CollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationField
CollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationField
/* "name" */
StateField ::= {EmbeddedClassStateField "."}* SimpleStateField
/* "u.name" */
SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField
/* "u.Group.name" */
/* "u.name" or "u.address.zip" (address = EmbeddedClassStateField) */
SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
/* "u.Group.name" */
SimpleStateFieldAssociationPathExpression ::= SingleValuedAssociationPathExpression "." StateField
@ -156,7 +156,7 @@ IndexBy ::= "INDEX" "BY" SimpleStateFieldPath
/*
* SELECT EXPRESSION
*/
SelectExpression ::= IdentificationVariable ["." "*"] | StateFieldPathExpression |
SelectExpression ::= IdentificationVariable | StateFieldPathExpression |
(AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable]
SimpleSelectExpression ::= SingleValuedPathExpression | IdentificationVariable | AggregateExpression
@ -164,21 +164,23 @@ SimpleSelectExpression ::= SingleValuedPathExpression | IdentificationVariable |
/*
* CONDITIONAL EXPRESSIONS
*/
ConditionalExpression ::= ConditionalTerm | ConditionalExpression "OR" ConditionalTerm
ConditionalTerm ::= ConditionalFactor | ConditionalTerm "AND" ConditionalFactor
ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
ConditionalFactor ::= ["NOT"] ConditionalPrimary
ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
SimpleConditionalExpression ::= ComparisonExpression | BetweenExpression | LikeExpression |
InExpression | NullComparisonExpression | ExistsExpression |
EmptyCollectionComparisonExpression | CollectionMemberExpression
SimpleConditionalExpression ::= ExistsExpression |
(SimpleStateFieldPathExpression (ComparisonExpression | BetweenExpression | LikeExpression |
InExpression | NullComparisonExpression)) |
(CollectionValuedPathExpression EmptyCollectionComparisonExpression) |
(EntityExpression CollectionMemberExpression)
/* EmptyCollectionComparisonExpression and CollectionMemberExpression are for the future */
/*
* COLLECTION EXPRESSIONS (FOR THE FUTURE)
*/
EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
EmptyCollectionComparisonExpression ::= "IS" ["NOT"] "EMPTY"
CollectionMemberExpression ::= ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
/*
@ -199,8 +201,8 @@ NamedParameter ::= ":" string
* ARITHMETIC EXPRESSIONS
*/
ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
SimpleArithmeticExpression ::= ArithmeticTerm | SimpleArithmeticExpression ("+"|"-") ArithmeticTerm
ArithmeticTerm ::= ArithmeticFactor | ArithmeticTerm ("*" |"/") ArithmeticFactor
SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*
ArithmeticTerm ::= ArithmeticFactor {("*" |"/") ArithmeticFactor}*
ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression

View File

@ -25,12 +25,13 @@ class Orm_Query_AllTests
$suite = new Doctrine_TestSuite('Doctrine Orm Query');
$suite->addTestSuite('Orm_Query_IdentifierRecognitionTest');
/*$suite->addTestSuite('Orm_Query_LanguageRecognitionTest');
$suite->addTestSuite('Orm_Query_SelectSqlGenerationTest');
/*
$suite->addTestSuite('Orm_Query_LanguageRecognitionTest');
$suite->addTestSuite('Orm_Query_ScannerTest');
$suite->addTestSuite('Orm_Query_DqlGenerationTest');
$suite->addTestSuite('Orm_Query_DeleteSqlGenerationTest');
$suite->addTestSuite('Orm_Query_UpdateSqlGenerationTest');
$suite->addTestSuite('Orm_Query_SelectSqlGenerationTest');*/
$suite->addTestSuite('Orm_Query_UpdateSqlGenerationTest');*/
return $suite;
}

View File

@ -24,8 +24,6 @@ require_once 'lib/DoctrineTestInit.php';
/**
* Test case for testing the saving and referencing of query identifiers.
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
@ -46,7 +44,7 @@ class Orm_Query_IdentifierRecognitionTest extends Doctrine_OrmTestCase
public function testSingleAliasDeclarationIsSupported()
{
$entityManager = $this->_em;
$query = $entityManager->createQuery('SELECT u.* FROM CmsUser u');
$query = $entityManager->createQuery('SELECT u FROM CmsUser u');
$parserResult = $query->parse();
$decl = $parserResult->getQueryComponent('u');
@ -61,7 +59,7 @@ class Orm_Query_IdentifierRecognitionTest extends Doctrine_OrmTestCase
public function testSingleAliasDeclarationWithIndexByIsSupported()
{
$entityManager = $this->_em;
$query = $entityManager->createQuery('SELECT u.* FROM CmsUser u INDEX BY u.id');
$query = $entityManager->createQuery('SELECT u FROM CmsUser u INDEX BY u.id');
$parserResult = $query->parse();
$decl = $parserResult->getQueryComponent('u');
@ -76,12 +74,12 @@ class Orm_Query_IdentifierRecognitionTest extends Doctrine_OrmTestCase
public function testQueryParserSupportsMultipleAliasDeclarations()
{
$entityManager = $this->_em;
$query = $entityManager->createQuery('SELECT u.* FROM CmsUser u INDEX BY u.id LEFT JOIN u.phonenumbers p');
$query = $entityManager->createQuery('SELECT u FROM CmsUser u INDEX BY u.id LEFT JOIN u.phonenumbers p');
$parserResult = $query->parse();
$decl = $parserResult->getQueryComponent('u');
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
$this->assertTrue($decl['metadata'] instanceof Doctrine_ORM_Mapping_ClassMetadata);
$this->assertEquals(null, $decl['relation']);
$this->assertEquals(null, $decl['parent']);
$this->assertEquals(null, $decl['scalar']);
@ -89,8 +87,8 @@ class Orm_Query_IdentifierRecognitionTest extends Doctrine_OrmTestCase
$decl = $parserResult->getQueryComponent('p');
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
$this->assertTrue($decl['relation'] instanceof Doctrine_Association);
$this->assertTrue($decl['metadata'] instanceof Doctrine_ORM_Mapping_ClassMetadata);
$this->assertTrue($decl['relation'] instanceof Doctrine_ORM_Mapping_AssociationMapping);
$this->assertEquals('u', $decl['parent']);
$this->assertEquals(null, $decl['scalar']);
$this->assertEquals(null, $decl['map']);
@ -100,12 +98,12 @@ class Orm_Query_IdentifierRecognitionTest extends Doctrine_OrmTestCase
public function testQueryParserSupportsMultipleAliasDeclarationsWithIndexBy()
{
$entityManager = $this->_em;
$query = $entityManager->createQuery('SELECT u.* FROM CmsUser u INDEX BY u.id LEFT JOIN u.articles a INNER JOIN u.phonenumbers pn INDEX BY pn.phonenumber');
$query = $entityManager->createQuery('SELECT u FROM CmsUser u INDEX BY u.id LEFT JOIN u.articles a INNER JOIN u.phonenumbers pn INDEX BY pn.phonenumber');
$parserResult = $query->parse();
$decl = $parserResult->getQueryComponent('u');
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
$this->assertTrue($decl['metadata'] instanceof Doctrine_ORM_Mapping_ClassMetadata);
$this->assertEquals(null, $decl['relation']);
$this->assertEquals(null, $decl['parent']);
$this->assertEquals(null, $decl['scalar']);
@ -113,16 +111,16 @@ class Orm_Query_IdentifierRecognitionTest extends Doctrine_OrmTestCase
$decl = $parserResult->getQueryComponent('a');
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
$this->assertTrue($decl['relation'] instanceof Doctrine_Association);
$this->assertTrue($decl['metadata'] instanceof Doctrine_ORM_Mapping_ClassMetadata);
$this->assertTrue($decl['relation'] instanceof Doctrine_ORM_Mapping_AssociationMapping);
$this->assertEquals('u', $decl['parent']);
$this->assertEquals(null, $decl['scalar']);
$this->assertEquals(null, $decl['map']);
$decl = $parserResult->getQueryComponent('pn');
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
$this->assertTrue($decl['relation'] instanceof Doctrine_Association);
$this->assertTrue($decl['metadata'] instanceof Doctrine_ORM_Mapping_ClassMetadata);
$this->assertTrue($decl['relation'] instanceof Doctrine_ORM_Mapping_AssociationMapping);
$this->assertEquals('u', $decl['parent']);
$this->assertEquals(null, $decl['scalar']);
$this->assertEquals('phonenumber', $decl['map']);

View File

@ -37,18 +37,20 @@ require_once 'lib/DoctrineTestInit.php';
*/
class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase
{
private $_em;
protected function setUp() {
$this->_em = $this->_getTestEntityManager();
}
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed)
{
try {
$entityManager = $this->_em;
$query = $entityManager->createQuery($dqlToBeTested);
//echo print_r($query->parse()->getQueryFields(), true) . "\n";
$query = $this->_em->createQuery($dqlToBeTested);
parent::assertEquals($sqlToBeConfirmed, $query->getSql());
//echo $query->getSql() . "\n";
$query->free();
} catch (Doctrine_Exception $e) {
echo $e->getTraceAsString(); die();
$this->fail($e->getMessage());
}
}
@ -57,71 +59,65 @@ class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase
public function testPlainFromClauseWithoutAlias()
{
$this->assertSqlGeneration(
'SELECT * FROM CmsUser',
'SELECT cu.id AS cu__id, cu.status AS cu__status, cu.username AS cu__username, cu.name AS cu__name FROM cms_user cu WHERE 1 = 1'
'SELECT u FROM CmsUser u',
'SELECT cu.id AS cu__id, cu.status AS cu__status, cu.username AS cu__username, cu.name AS cu__name FROM CmsUser cu'
);
$this->assertSqlGeneration(
'SELECT id FROM CmsUser',
'SELECT cu.id AS cu__id FROM cms_user cu WHERE 1 = 1'
'SELECT u.id FROM CmsUser u',
'SELECT cu.id AS cu__id FROM CmsUser cu'
);
}
public function testPlainFromClauseWithAlias()
{
$this->assertSqlGeneration(
'SELECT u.id FROM CmsUser u',
'SELECT cu.id AS cu__id FROM cms_user cu WHERE 1 = 1'
);
}
public function testSelectSingleComponentWithAsterisk()
{
$this->assertSqlGeneration(
'SELECT u.* FROM CmsUser u',
'SELECT cu.id AS cu__id, cu.status AS cu__status, cu.username AS cu__username, cu.name AS cu__name FROM cms_user cu WHERE 1 = 1'
);
}
public function testSelectSingleComponentWithMultipleColumns()
{
$this->assertSqlGeneration(
'SELECT u.username, u.name FROM CmsUser u',
'SELECT cu.username AS cu__username, cu.name AS cu__name FROM cms_user cu WHERE 1 = 1'
'SELECT cu.username AS cu__username, cu.name AS cu__name FROM CmsUser cu'
);
}
public function testSelectMultipleComponentsWithAsterisk()
public function testSelectWithCollectionAssociationJoin()
{
$this->assertSqlGeneration(
'SELECT u.*, p.* FROM CmsUser u, u.phonenumbers p',
'SELECT cu.id AS cu__id, cu.status AS cu__status, cu.username AS cu__username, cu.name AS cu__name, cp.user_id AS cp__user_id, cp.phonenumber AS cp__phonenumber FROM cms_user cu, cms_phonenumber cp WHERE 1 = 1'
'SELECT u, p FROM CmsUser u JOIN u.phonenumbers p',
'SELECT cu.id AS cu__id, cu.status AS cu__status, cu.username AS cu__username, cu.name AS cu__name, cp.phonenumber AS cp__phonenumber FROM CmsUser cu INNER JOIN CmsPhonenumber cp ON cu.id = cp.user_id'
);
}
public function testSelectWithSingleValuedAssociationJoin()
{
$this->assertSqlGeneration(
'SELECT u, a FROM ForumUser u JOIN u.avatar a',
'SELECT fu.id AS fu__id, fu.username AS fu__username, fa.id AS fa__id FROM ForumUser fu INNER JOIN ForumAvatar fa ON fu.avatar_id = fa.id'
);
}
public function testSelectDistinctIsSupported()
{
$this->assertSqlGeneration(
'SELECT DISTINCT u.name FROM CmsUser u',
'SELECT DISTINCT cu.name AS cu__name FROM cms_user cu WHERE 1 = 1'
'SELECT DISTINCT cu.name AS cu__name FROM CmsUser cu'
);
}
public function testAggregateFunctionInSelect()
{
$this->assertSqlGeneration(
'SELECT COUNT(u.id) FROM CmsUser u GROUP BY u.id',
'SELECT COUNT(cu.id) AS dctrn__0 FROM cms_user cu WHERE 1 = 1 GROUP BY cu.id'
'SELECT COUNT(cu.id) AS dctrn__0 FROM CmsUser cu GROUP BY cu.id'
);
}
public function testAggregateFunctionWithDistinctInSelect()
/* public function testWhereClauseInSelect()
{
$this->assertSqlGeneration(
'select u from ForumUser u where u.id = ?',
'SELECT fu.id AS fu__id, fu.username AS fu__username FROM ForumUser fu WHERE fu.id = ?'
);
}
*/
/* public function testAggregateFunctionWithDistinctInSelect()
{
$this->assertSqlGeneration(
'SELECT COUNT(DISTINCT u.name) FROM CmsUser u',
@ -209,5 +205,5 @@ class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase
'SELECT cu.id AS cu__id, ca.id AS ca__id FROM cms_user cu INNER JOIN cms_article ca ON cu.id = ca.user_id WHERE 1 = 1'
);
}
*/
}