Commit 602c6d97 authored by romanb's avatar romanb

DQL Parser work. Getting some first tests back running. Reorganizing all...

DQL Parser work. Getting some first tests back running. Reorganizing all parser rules into the Parser itself.
parent f0a302ec
......@@ -118,4 +118,3 @@ class Doctrine_ORM_Mapping_OneToManyMapping extends Doctrine_ORM_Mapping_Associa
}
?>
\ No newline at end of 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;
}
}
\ No newline at end of file
<?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;
}
}
<?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
{
}
<?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;
}
}
<?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;
}
}
<?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;
}
}
<?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)
{
$this->_identificationVariableDeclarations[] = $identificationVariableDeclaration;
}
public function setIdentificationVariableDeclarations($identificationVariableDeclarations, $append = false)
public function __construct(array $identificationVariableDeclarations)
{
$this->_selectExpressions = ($append === true)
? array_merge($this->_identificationVariableDeclarations, $identificationVariableDeclarations)
: $identificationVariableDeclarations;
$this->_identificationVariableDeclarations = $identificationVariableDeclarations;
}
/* Getters */
public function getIdentificationVariableDeclarations()
{
......
<?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)
{
......
<?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()
{
......
<?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)
{
$this->_abstractSchemaName = $abstractSchemaName;
}
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()
{
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)
{
$this->_isDistinct = $value;
}
public function addSelectExpression($expression)
public function __construct(array $selectExpressions, $isDistinct)
{
$this->_selectExpressions[] = $expression;
$this->_isDistinct = $isDistinct;
$this->_selectExpressions = $selectExpressions;
}
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() : '');
......
<?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()
{
......
<?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()
));
}
}
\ No newline at end of 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.
*
......@@ -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());
}
......
<?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);
}
}
<?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
{
}
<?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
{
}
\ No newline at end of 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);
}
}
......
......@@ -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)
......
<?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()
public function testSelectSingleComponentWithMultipleColumns()
{
$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'
'SELECT u.username, u.name FROM CmsUser u',
'SELECT cu.username AS cu__username, cu.name AS cu__name FROM CmsUser cu'
);
}
public function testSelectSingleComponentWithMultipleColumns()
public function testSelectWithCollectionAssociationJoin()
{
$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 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 testSelectMultipleComponentsWithAsterisk()
public function testSelectWithSingleValuedAssociationJoin()
{
$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, 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'
);
}
*/
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment