DQL Parser work. Getting some first tests back running. Reorganizing all parser rules into the Parser itself.
This commit is contained in:
parent
f0a302ec8d
commit
602c6d973e
@ -118,4 +118,3 @@ class Doctrine_ORM_Mapping_OneToManyMapping extends Doctrine_ORM_Mapping_Associa
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -31,11 +31,4 @@
|
||||
*/
|
||||
abstract class Doctrine_ORM_Query_AST
|
||||
{
|
||||
protected $_parserResult = null;
|
||||
|
||||
|
||||
public function __construct(Doctrine_ORM_Query_ParserResult $parserResult)
|
||||
{
|
||||
$this->_parserResult = $parserResult;
|
||||
}
|
||||
}
|
40
lib/Doctrine/ORM/Query/AST/AggregateExpression.php
Normal file
40
lib/Doctrine/ORM/Query/AST/AggregateExpression.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
16
lib/Doctrine/ORM/Query/AST/ComparisonExpression.php
Normal file
16
lib/Doctrine/ORM/Query/AST/ComparisonExpression.php
Normal 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
|
||||
{
|
||||
|
||||
}
|
||||
|
26
lib/Doctrine/ORM/Query/AST/ConditionalExpression.php
Normal file
26
lib/Doctrine/ORM/Query/AST/ConditionalExpression.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
33
lib/Doctrine/ORM/Query/AST/ConditionalFactor.php
Normal file
33
lib/Doctrine/ORM/Query/AST/ConditionalFactor.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
37
lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php
Normal file
37
lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
26
lib/Doctrine/ORM/Query/AST/ConditionalTerm.php
Normal file
26
lib/Doctrine/ORM/Query/AST/ConditionalTerm.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -32,22 +32,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;
|
||||
$this->_identificationVariableDeclarations = $identificationVariableDeclarations;
|
||||
}
|
||||
|
||||
|
||||
public function setIdentificationVariableDeclarations($identificationVariableDeclarations, $append = false)
|
||||
{
|
||||
$this->_selectExpressions = ($append === true)
|
||||
? array_merge($this->_identificationVariableDeclarations, $identificationVariableDeclarations)
|
||||
: $identificationVariableDeclarations;
|
||||
}
|
||||
|
||||
|
||||
/* Getters */
|
||||
public function getIdentificationVariableDeclarations()
|
||||
{
|
||||
|
26
lib/Doctrine/ORM/Query/AST/GroupByClause.php
Normal file
26
lib/Doctrine/ORM/Query/AST/GroupByClause.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -36,34 +36,13 @@ class Doctrine_ORM_Query_AST_IdentificationVariableDeclaration extends Doctrine_
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -32,14 +32,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()
|
||||
{
|
||||
|
@ -53,22 +53,14 @@ class Doctrine_ORM_Query_AST_Join extends Doctrine_ORM_Query_AST
|
||||
|
||||
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)
|
||||
{
|
||||
|
33
lib/Doctrine/ORM/Query/AST/JoinPathExpression.php
Normal file
33
lib/Doctrine/ORM/Query/AST/JoinPathExpression.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -34,20 +34,12 @@ 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()
|
||||
{
|
||||
|
86
lib/Doctrine/ORM/Query/AST/PathExpression.php
Normal file
86
lib/Doctrine/ORM/Query/AST/PathExpression.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -30,36 +30,33 @@
|
||||
*/
|
||||
class Doctrine_ORM_Query_AST_RangeVariableDeclaration extends Doctrine_ORM_Query_AST
|
||||
{
|
||||
protected $_abstractSchemaName = null;
|
||||
private $_classMetadata;
|
||||
private $_abstractSchemaName;
|
||||
private $_aliasIdentificationVariable;
|
||||
|
||||
protected $_aliasIdentificationVariable = null;
|
||||
|
||||
|
||||
/* Setters */
|
||||
public function setAbstractSchemaName($abstractSchemaName)
|
||||
public function __construct($classMetadata, $aliasIdentificationVar)
|
||||
{
|
||||
$this->_abstractSchemaName = $abstractSchemaName;
|
||||
$this->_classMetadata = $classMetadata;
|
||||
$this->_abstractSchemaName = $classMetadata->getClassName();
|
||||
$this->_aliasIdentificationVariable = $aliasIdentificationVar;
|
||||
}
|
||||
|
||||
|
||||
public function setAliasIdentificationVariable($aliasIdentificationVariable)
|
||||
{
|
||||
$this->_aliasIdentificationVariable = $aliasIdentificationVariable;
|
||||
}
|
||||
|
||||
|
||||
/* Getters */
|
||||
public function getAbstractSchemaName()
|
||||
{
|
||||
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" */
|
||||
|
||||
|
@ -34,28 +34,12 @@ class Doctrine_ORM_Query_AST_SelectClause extends Doctrine_ORM_Query_AST
|
||||
|
||||
protected $_selectExpressions = array();
|
||||
|
||||
|
||||
/* Setters */
|
||||
public function setIsDistinct($value)
|
||||
public function __construct(array $selectExpressions, $isDistinct)
|
||||
{
|
||||
$this->_isDistinct = $value;
|
||||
$this->_isDistinct = $isDistinct;
|
||||
$this->_selectExpressions = $selectExpressions;
|
||||
}
|
||||
|
||||
|
||||
public function addSelectExpression($expression)
|
||||
{
|
||||
$this->_selectExpressions[] = $expression;
|
||||
}
|
||||
|
||||
|
||||
public function setSelectExpressions($expressions, $append = false)
|
||||
{
|
||||
$this->_selectExpressions = ($append === true)
|
||||
? array_merge($this->_selectExpressions, $expressions)
|
||||
: $expressions;
|
||||
}
|
||||
|
||||
|
||||
/* Getters */
|
||||
public function isDistinct()
|
||||
{
|
||||
|
@ -35,19 +35,12 @@ class Doctrine_ORM_Query_AST_SelectExpression extends Doctrine_ORM_Query_AST
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -31,55 +31,22 @@
|
||||
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() : '');
|
||||
|
16
lib/Doctrine/ORM/Query/AST/SimpleConditionalExpression.php
Normal file
16
lib/Doctrine/ORM/Query/AST/SimpleConditionalExpression.php
Normal 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
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -34,20 +34,12 @@ class Doctrine_ORM_Query_AST_SimpleStateFieldPathExpression extends Doctrine_ORM
|
||||
|
||||
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()
|
||||
{
|
||||
|
26
lib/Doctrine/ORM/Query/AST/WhereClause.php
Normal file
26
lib/Doctrine/ORM/Query/AST/WhereClause.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
));
|
||||
}
|
||||
|
||||
}
|
@ -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.
|
||||
*
|
||||
@ -363,18 +345,683 @@ class Doctrine_ORM_Query_Parser
|
||||
return $this->_em;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the piece of DQL string given the token position
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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'));
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
{
|
||||
|
||||
}
|
@ -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
|
||||
{
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
254
lib/Doctrine/ORM/Query/SqlWalker.php
Normal file
254
lib/Doctrine/ORM/Query/SqlWalker.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ CollectionValuedPathExpression ::= IdentificationVariable "." {Single
|
||||
/* "name" */
|
||||
StateField ::= {EmbeddedClassStateField "."}* SimpleStateField
|
||||
|
||||
/* "u.name" */
|
||||
SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField
|
||||
/* "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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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']);
|
||||
|
@ -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'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testPlainFromClauseWithAlias()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT u.id FROM CmsUser u',
|
||||
'SELECT cu.id AS cu__id FROM cms_user cu WHERE 1 = 1'
|
||||
'SELECT cu.id AS cu__id FROM CmsUser cu'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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'
|
||||
);
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
Loading…
Reference in New Issue
Block a user