Updated PoC for multiple components DQL support.
This commit is contained in:
parent
e7dfa08756
commit
41a650b699
@ -25,3 +25,8 @@ Also, related functions were affected:
|
|||||||
* setParameters($parameters) the argument $parameters can be either an key=>value array or an ArrayCollection instance
|
* setParameters($parameters) the argument $parameters can be either an key=>value array or an ArrayCollection instance
|
||||||
* getParameters() now returns ArrayCollection instead of array
|
* getParameters() now returns ArrayCollection instead of array
|
||||||
* getParameter($key) now returns Parameter instance instead of parameter value
|
* getParameter($key) now returns Parameter instance instead of parameter value
|
||||||
|
|
||||||
|
# Query TreeWalker method renamed
|
||||||
|
|
||||||
|
Internal changes were made to DQL and SQL generation. If you have implemented your own TreeWalker,
|
||||||
|
you probably need to update it. The method walkJoinVariableDeclaration is now named walkJoin.
|
||||||
|
@ -36,13 +36,13 @@ class IdentificationVariableDeclaration extends Node
|
|||||||
{
|
{
|
||||||
public $rangeVariableDeclaration = null;
|
public $rangeVariableDeclaration = null;
|
||||||
public $indexBy = null;
|
public $indexBy = null;
|
||||||
public $joinVariableDeclarations = array();
|
public $joins = array();
|
||||||
|
|
||||||
public function __construct($rangeVariableDecl, $indexBy, array $joinVariableDecls)
|
public function __construct($rangeVariableDecl, $indexBy, array $joins)
|
||||||
{
|
{
|
||||||
$this->rangeVariableDeclaration = $rangeVariableDecl;
|
$this->rangeVariableDeclaration = $rangeVariableDecl;
|
||||||
$this->indexBy = $indexBy;
|
$this->indexBy = $indexBy;
|
||||||
$this->joinVariableDeclarations = $joinVariableDecls;
|
$this->joins = $joins;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch($sqlWalker)
|
public function dispatch($sqlWalker)
|
||||||
|
@ -25,10 +25,8 @@ namespace Doctrine\ORM\Query\AST;
|
|||||||
* Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
|
* Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
|
||||||
* ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression]
|
* ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression]
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @link www.doctrine-project.org
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision: 3938 $
|
|
||||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
* @author Jonathan Wage <jonwage@gmail.com>
|
* @author Jonathan Wage <jonwage@gmail.com>
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
@ -40,13 +38,13 @@ class Join extends Node
|
|||||||
const JOIN_TYPE_INNER = 3;
|
const JOIN_TYPE_INNER = 3;
|
||||||
|
|
||||||
public $joinType = self::JOIN_TYPE_INNER;
|
public $joinType = self::JOIN_TYPE_INNER;
|
||||||
public $joinPathExpression = null;
|
public $joinAssociationDeclaration = null;
|
||||||
public $conditionalExpression = null;
|
public $conditionalExpression = null;
|
||||||
|
|
||||||
public function __construct($joinType, $joinPathExpr)
|
public function __construct($joinType, $joinAssociationDeclaration)
|
||||||
{
|
{
|
||||||
$this->joinType = $joinType;
|
$this->joinType = $joinType;
|
||||||
$this->joinAssociationPathExpression = $joinPathExpr;
|
$this->joinAssociationDeclaration = $joinAssociationDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch($sqlWalker)
|
public function dispatch($sqlWalker)
|
||||||
|
@ -15,36 +15,39 @@
|
|||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* This software consists of voluntary contributions made by many individuals
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
<<<<<<< HEAD:lib/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php
|
||||||
* and is licensed under the MIT license. For more information, see
|
* and is licensed under the MIT license. For more information, see
|
||||||
* <http://www.phpdoctrine.org>.
|
* <http://www.phpdoctrine.org>.
|
||||||
|
=======
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
>>>>>>> Updated PoC for multiple components DQL support.:lib/Doctrine/ORM/Query/AST/JoinAssociationDeclaration.php
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Doctrine\ORM\Query\AST;
|
namespace Doctrine\ORM\Query\AST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JoinVariableDeclaration ::= Join [IndexBy]
|
* JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* @link www.doctrine-project.org
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.3
|
||||||
* @version $Revision: 3938 $
|
|
||||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
* @author Jonathan Wage <jonwage@gmail.com>
|
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
|
||||||
*/
|
*/
|
||||||
class JoinVariableDeclaration extends Node
|
class JoinAssociationDeclaration extends Node
|
||||||
{
|
{
|
||||||
public $join = null;
|
public $joinAssociationPathExpression;
|
||||||
public $indexBy = null;
|
public $aliasIdentificationVariable;
|
||||||
|
public $indexBy;
|
||||||
|
|
||||||
public function __construct($join, $indexBy)
|
public function __construct($joinAssociationPathExpression, $aliasIdentificationVariable, $indexBy)
|
||||||
{
|
{
|
||||||
$this->join = $join;
|
$this->joinAssociationPathExpression = $joinAssociationPathExpression;
|
||||||
|
$this->aliasIdentificationVariable = $aliasIdentificationVariable;
|
||||||
$this->indexBy = $indexBy;
|
$this->indexBy = $indexBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch($sqlWalker)
|
public function dispatch($sqlWalker)
|
||||||
{
|
{
|
||||||
return $sqlWalker->walkJoinVariableDeclaration($this);
|
return $sqlWalker->walkJoinAssociationDeclaration($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,10 +24,8 @@ namespace Doctrine\ORM\Query\AST;
|
|||||||
/**
|
/**
|
||||||
* JoinAssociationPathExpression ::= IdentificationVariable "." (SingleValuedAssociationField | CollectionValuedAssociationField)
|
* JoinAssociationPathExpression ::= IdentificationVariable "." (SingleValuedAssociationField | CollectionValuedAssociationField)
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @link www.doctrine-project.org
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision: 3938 $
|
|
||||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
* @author Jonathan Wage <jonwage@gmail.com>
|
* @author Jonathan Wage <jonwage@gmail.com>
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
@ -36,17 +34,15 @@ class JoinAssociationPathExpression extends Node
|
|||||||
{
|
{
|
||||||
public $identificationVariable;
|
public $identificationVariable;
|
||||||
public $associationField;
|
public $associationField;
|
||||||
public $aliasIdentificationVariable = null;
|
|
||||||
|
|
||||||
public function __construct($identificationVariable, $associationField, $aliasIdentVar)
|
public function __construct($identificationVariable, $associationField)
|
||||||
{
|
{
|
||||||
$this->identificationVariable = $identificationVariable;
|
$this->identificationVariable = $identificationVariable;
|
||||||
$this->associationField = $associationField;
|
$this->associationField = $associationField;
|
||||||
$this->aliasIdentificationVariable = $aliasIdentVar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch($sqlWalker)
|
public function dispatch($sqlWalker)
|
||||||
{
|
{
|
||||||
return $sqlWalker->walkJoinPathExpression($this);
|
return $sqlWalker->walkPathExpression($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -909,58 +909,7 @@ class Parser
|
|||||||
$this->semanticalError('Class ' . $class->name . ' has no association named ' . $field);
|
$this->semanticalError('Class ' . $class->name . ' has no association named ' . $field);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
return new AST\JoinAssociationPathExpression($identVariable, $field);
|
||||||
$this->match(Lexer::T_AS);
|
|
||||||
}
|
|
||||||
|
|
||||||
$token = $this->_lexer->lookahead;
|
|
||||||
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
|
|
||||||
|
|
||||||
// Building queryComponent
|
|
||||||
$joinQueryComponent = array(
|
|
||||||
'metadata' => $this->_em->getClassMetadata($class->associationMappings[$field]['targetEntity']),
|
|
||||||
'parent' => $identVariable,
|
|
||||||
'relation' => $class->getAssociationMapping($field),
|
|
||||||
'map' => null,
|
|
||||||
'nestingLevel' => $this->_nestingLevel,
|
|
||||||
'token' => $this->_lexer->lookahead
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent;
|
|
||||||
|
|
||||||
return new AST\JoinAssociationPathExpression($identVariable, $field, $aliasIdentificationVariable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JoinClassPathExpression ::= Class alias
|
|
||||||
*
|
|
||||||
* @return \Doctrine\ORM\Query\AST\JoinClassPathExpression
|
|
||||||
*/
|
|
||||||
public function JoinClassPathExpression()
|
|
||||||
{
|
|
||||||
$abstractSchemaName = $this->AbstractSchemaName();
|
|
||||||
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
|
||||||
$this->match(Lexer::T_AS);
|
|
||||||
}
|
|
||||||
|
|
||||||
$token = $this->_lexer->lookahead;
|
|
||||||
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
|
|
||||||
$classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
|
|
||||||
|
|
||||||
// Building queryComponent
|
|
||||||
$queryComponent = array(
|
|
||||||
'metadata' => $classMetadata,
|
|
||||||
'parent' => null,
|
|
||||||
'relation' => null,
|
|
||||||
'map' => null,
|
|
||||||
'nestingLevel' => $this->_nestingLevel,
|
|
||||||
'token' => $token
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
|
|
||||||
|
|
||||||
return new AST\JoinClassPathExpression($abstractSchemaName, $aliasIdentificationVariable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1452,7 +1401,7 @@ class Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
|
* IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {Join}*
|
||||||
*
|
*
|
||||||
* @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
|
* @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
|
||||||
*/
|
*/
|
||||||
@ -1460,18 +1409,18 @@ class Parser
|
|||||||
{
|
{
|
||||||
$rangeVariableDeclaration = $this->RangeVariableDeclaration();
|
$rangeVariableDeclaration = $this->RangeVariableDeclaration();
|
||||||
$indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
|
$indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
|
||||||
$joinVariableDeclarations = array();
|
$joins = array();
|
||||||
|
|
||||||
while (
|
while (
|
||||||
$this->_lexer->isNextToken(Lexer::T_LEFT) ||
|
$this->_lexer->isNextToken(Lexer::T_LEFT) ||
|
||||||
$this->_lexer->isNextToken(Lexer::T_INNER) ||
|
$this->_lexer->isNextToken(Lexer::T_INNER) ||
|
||||||
$this->_lexer->isNextToken(Lexer::T_JOIN)
|
$this->_lexer->isNextToken(Lexer::T_JOIN)
|
||||||
) {
|
) {
|
||||||
$joinVariableDeclarations[] = $this->JoinVariableDeclaration();
|
$joins[] = $this->Join();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AST\IdentificationVariableDeclaration(
|
return new AST\IdentificationVariableDeclaration(
|
||||||
$rangeVariableDeclaration, $indexBy, $joinVariableDeclarations
|
$rangeVariableDeclaration, $indexBy, $joins
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1501,16 +1450,57 @@ class Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JoinVariableDeclaration ::= Join [IndexBy]
|
* Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN"
|
||||||
|
* (JoinAssociationDeclaration | RangeVariableDeclaration)
|
||||||
|
* ["WITH" ConditionalExpression]
|
||||||
*
|
*
|
||||||
* @return \Doctrine\ORM\Query\AST\JoinVariableDeclaration
|
* @return \Doctrine\ORM\Query\AST\Join
|
||||||
*/
|
*/
|
||||||
public function JoinVariableDeclaration()
|
public function Join()
|
||||||
{
|
{
|
||||||
$join = $this->Join();
|
// Check Join type
|
||||||
$indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
|
$joinType = AST\Join::JOIN_TYPE_INNER;
|
||||||
|
|
||||||
return new AST\JoinVariableDeclaration($join, $indexBy);
|
switch (true) {
|
||||||
|
case ($this->_lexer->isNextToken(Lexer::T_LEFT)):
|
||||||
|
$this->match(Lexer::T_LEFT);
|
||||||
|
|
||||||
|
$joinType = AST\Join::JOIN_TYPE_LEFT;
|
||||||
|
|
||||||
|
// Possible LEFT OUTER join
|
||||||
|
if ($this->_lexer->isNextToken(Lexer::T_OUTER)) {
|
||||||
|
$this->match(Lexer::T_OUTER);
|
||||||
|
|
||||||
|
$joinType = AST\Join::JOIN_TYPE_LEFTOUTER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($this->_lexer->isNextToken(Lexer::T_INNER)):
|
||||||
|
$this->match(Lexer::T_INNER);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->match(Lexer::T_JOIN);
|
||||||
|
|
||||||
|
$next = $this->_lexer->glimpse();
|
||||||
|
$joinDeclaration = ($next['type'] === Lexer::T_DOT)
|
||||||
|
? $this->JoinAssociationDeclaration()
|
||||||
|
: $this->RangeVariableDeclaration();
|
||||||
|
|
||||||
|
// Create AST node
|
||||||
|
$join = new AST\Join($joinType, $joinDeclaration);
|
||||||
|
|
||||||
|
// Check for ad-hoc Join conditions
|
||||||
|
if ($this->_lexer->isNextToken(Lexer::T_WITH) || $joinDeclaration instanceof AST\RangeVariableDeclaration) {
|
||||||
|
$this->match(Lexer::T_WITH);
|
||||||
|
|
||||||
|
$join->conditionalExpression = $this->ConditionalExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $join;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1545,6 +1535,43 @@ class Parser
|
|||||||
return new AST\RangeVariableDeclaration($abstractSchemaName, $aliasIdentificationVariable);
|
return new AST\RangeVariableDeclaration($abstractSchemaName, $aliasIdentificationVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
|
||||||
|
*
|
||||||
|
* @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression
|
||||||
|
*/
|
||||||
|
public function JoinAssociationDeclaration()
|
||||||
|
{
|
||||||
|
$joinAssociationPathExpression = $this->JoinAssociationPathExpression();
|
||||||
|
|
||||||
|
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
||||||
|
$this->match(Lexer::T_AS);
|
||||||
|
}
|
||||||
|
|
||||||
|
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
|
||||||
|
$indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
|
||||||
|
|
||||||
|
$identificationVariable = $joinAssociationPathExpression->identificationVariable;
|
||||||
|
$field = $joinAssociationPathExpression->associationField;
|
||||||
|
|
||||||
|
$class = $this->_queryComponents[$identificationVariable]['metadata'];
|
||||||
|
$targetClass = $this->_em->getClassMetadata($class->associationMappings[$field]['targetEntity']);
|
||||||
|
|
||||||
|
// Building queryComponent
|
||||||
|
$joinQueryComponent = array(
|
||||||
|
'metadata' => $targetClass,
|
||||||
|
'parent' => $joinAssociationPathExpression->identificationVariable,
|
||||||
|
'relation' => $class->getAssociationMapping($field),
|
||||||
|
'map' => null,
|
||||||
|
'nestingLevel' => $this->_nestingLevel,
|
||||||
|
'token' => $this->_lexer->lookahead
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent;
|
||||||
|
|
||||||
|
return new AST\JoinAssociationDeclaration($joinAssociationPathExpression, $aliasIdentificationVariable, $indexBy);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
|
* PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
|
||||||
* PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
|
* PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
|
||||||
@ -1586,65 +1613,6 @@ class Parser
|
|||||||
return $partialObjectExpression;
|
return $partialObjectExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
|
|
||||||
* ["AS"] AliasIdentificationVariable ["WITH" ConditionalExpression]
|
|
||||||
*
|
|
||||||
* @return \Doctrine\ORM\Query\AST\Join
|
|
||||||
*/
|
|
||||||
public function Join()
|
|
||||||
{
|
|
||||||
// Check Join type
|
|
||||||
$joinType = AST\Join::JOIN_TYPE_INNER;
|
|
||||||
|
|
||||||
switch (true) {
|
|
||||||
case ($this->_lexer->isNextToken(Lexer::T_LEFT)):
|
|
||||||
$this->match(Lexer::T_LEFT);
|
|
||||||
|
|
||||||
$joinType = AST\Join::JOIN_TYPE_LEFT;
|
|
||||||
|
|
||||||
// Possible LEFT OUTER join
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_OUTER)) {
|
|
||||||
$this->match(Lexer::T_OUTER);
|
|
||||||
|
|
||||||
$joinType = AST\Join::JOIN_TYPE_LEFTOUTER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ($this->_lexer->isNextToken(Lexer::T_INNER)):
|
|
||||||
$this->match(Lexer::T_INNER);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->match(Lexer::T_JOIN);
|
|
||||||
|
|
||||||
$next = $this->_lexer->glimpse();
|
|
||||||
if ($next['type'] === Lexer::T_DOT) {
|
|
||||||
$joinPathExpression = $this->JoinAssociationPathExpression();
|
|
||||||
} else {
|
|
||||||
$joinPathExpression = $this->JoinClassPathExpression();
|
|
||||||
|
|
||||||
if (!$this->_lexer->isNextToken(Lexer::T_WITH)) {
|
|
||||||
$this->syntaxError('WITH');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create AST node
|
|
||||||
$join = new AST\Join($joinType, $joinPathExpression);
|
|
||||||
|
|
||||||
// Check for ad-hoc Join conditions
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_WITH)) {
|
|
||||||
$this->match(Lexer::T_WITH);
|
|
||||||
|
|
||||||
$join->conditionalExpression = $this->ConditionalExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $join;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IndexBy ::= "INDEX" "BY" StateFieldPathExpression
|
* IndexBy ::= "INDEX" "BY" StateFieldPathExpression
|
||||||
*
|
*
|
||||||
|
@ -705,23 +705,10 @@ class SqlWalker implements TreeWalker
|
|||||||
$sqlParts = array();
|
$sqlParts = array();
|
||||||
|
|
||||||
foreach ($identificationVarDecls as $identificationVariableDecl) {
|
foreach ($identificationVarDecls as $identificationVariableDecl) {
|
||||||
$sql = '';
|
$sql = $this->walkRangeVariableDeclaration($identificationVariableDecl->rangeVariableDeclaration);
|
||||||
|
|
||||||
$rangeDecl = $identificationVariableDecl->rangeVariableDeclaration;
|
foreach ($identificationVariableDecl->joins as $join) {
|
||||||
$dqlAlias = $rangeDecl->aliasIdentificationVariable;
|
$sql .= $this->walkJoin($join);
|
||||||
|
|
||||||
$this->_rootAliases[] = $dqlAlias;
|
|
||||||
|
|
||||||
$class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName);
|
|
||||||
$sql .= $class->getQuotedTableName($this->_platform) . ' '
|
|
||||||
. $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
|
||||||
|
|
||||||
if ($class->isInheritanceTypeJoined()) {
|
|
||||||
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($identificationVariableDecl->joinVariableDeclarations as $joinVarDecl) {
|
|
||||||
$sql .= $this->walkJoinVariableDeclaration($joinVarDecl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($identificationVariableDecl->indexBy) {
|
if ($identificationVariableDecl->indexBy) {
|
||||||
@ -744,6 +731,174 @@ class SqlWalker implements TreeWalker
|
|||||||
return ' FROM ' . implode(', ', $sqlParts);
|
return ' FROM ' . implode(', ', $sqlParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks down a RangeVariableDeclaration AST node, thereby generating the appropriate SQL.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function walkRangeVariableDeclaration($rangeVariableDeclaration)
|
||||||
|
{
|
||||||
|
$class = $this->_em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName);
|
||||||
|
$dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable;
|
||||||
|
|
||||||
|
$this->_rootAliases[] = $dqlAlias;
|
||||||
|
|
||||||
|
$sql = $class->getQuotedTableName($this->_platform) . ' '
|
||||||
|
. $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||||
|
|
||||||
|
if ($class->isInheritanceTypeJoined()) {
|
||||||
|
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks down a JoinAssociationDeclaration AST node, thereby generating the appropriate SQL.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function walkJoinAssociationDeclaration($joinAssociationDeclaration, $joinType = AST\Join::JOIN_TYPE_INNER)
|
||||||
|
{
|
||||||
|
$sql = '';
|
||||||
|
|
||||||
|
$associationPathExpression = $joinAssociationDeclaration->joinAssociationPathExpression;
|
||||||
|
$joinedDqlAlias = $joinAssociationDeclaration->aliasIdentificationVariable;
|
||||||
|
$indexBy = $joinAssociationDeclaration->indexBy;
|
||||||
|
|
||||||
|
$relation = $this->_queryComponents[$joinedDqlAlias]['relation'];
|
||||||
|
$targetClass = $this->_em->getClassMetadata($relation['targetEntity']);
|
||||||
|
$sourceClass = $this->_em->getClassMetadata($relation['sourceEntity']);
|
||||||
|
$targetTableName = $targetClass->getQuotedTableName($this->_platform);
|
||||||
|
|
||||||
|
$targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias);
|
||||||
|
$sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $associationPathExpression->identificationVariable);
|
||||||
|
|
||||||
|
// Ensure we got the owning side, since it has all mapping info
|
||||||
|
$assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation;
|
||||||
|
|
||||||
|
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true && (!$this->_query->getHint(self::HINT_DISTINCT) || isset($this->_selectedClasses[$joinedDqlAlias]))) {
|
||||||
|
if ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) {
|
||||||
|
throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot
|
||||||
|
// be the owning side and previously we ensured that $assoc is always the owning side of the associations.
|
||||||
|
// The owning side is necessary at this point because only it contains the JoinColumn information.
|
||||||
|
switch (true) {
|
||||||
|
case ($assoc['type'] & ClassMetadata::TO_ONE):
|
||||||
|
$conditions = array();
|
||||||
|
|
||||||
|
foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) {
|
||||||
|
if ($relation['isOwningSide']) {
|
||||||
|
$quotedTargetColumn = ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$targetColumn]))
|
||||||
|
? $targetColumn // Join columns cannot be quoted.
|
||||||
|
: $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
|
||||||
|
|
||||||
|
$conditions[] = $sourceTableAlias . '.' . $sourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$quotedTargetColumn = ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$targetColumn]))
|
||||||
|
? $targetColumn // Join columns cannot be quoted.
|
||||||
|
: $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
|
||||||
|
|
||||||
|
$conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply remaining inheritance restrictions
|
||||||
|
$discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($joinedDqlAlias));
|
||||||
|
|
||||||
|
if ($discrSql) {
|
||||||
|
$conditions[] = $discrSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the filters
|
||||||
|
$filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias);
|
||||||
|
|
||||||
|
if ($filterExpr) {
|
||||||
|
$conditions[] = $filterExpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($assoc['type'] == ClassMetadata::MANY_TO_MANY):
|
||||||
|
// Join relation table
|
||||||
|
$joinTable = $assoc['joinTable'];
|
||||||
|
$joinTableAlias = $this->getSQLTableAlias($joinTable['name'], $joinedDqlAlias);
|
||||||
|
$joinTableName = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform);
|
||||||
|
|
||||||
|
$conditions = array();
|
||||||
|
$relationColumns = ($relation['isOwningSide'])
|
||||||
|
? $assoc['relationToSourceKeyColumns']
|
||||||
|
: $assoc['relationToTargetKeyColumns'];
|
||||||
|
|
||||||
|
foreach ($relationColumns as $relationColumn => $sourceColumn) {
|
||||||
|
$quotedTargetColumn = ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$sourceColumn]))
|
||||||
|
? $sourceColumn // Join columns cannot be quoted.
|
||||||
|
: $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform);
|
||||||
|
|
||||||
|
$conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= $joinTableName . ' ' . $joinTableAlias . ' ON ' . implode(' AND ', $conditions);
|
||||||
|
|
||||||
|
// Join target table
|
||||||
|
$sql .= ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) ? ' LEFT JOIN ' : ' INNER JOIN ';
|
||||||
|
|
||||||
|
$conditions = array();
|
||||||
|
$relationColumns = ($relation['isOwningSide'])
|
||||||
|
? $assoc['relationToTargetKeyColumns']
|
||||||
|
: $assoc['relationToSourceKeyColumns'];
|
||||||
|
|
||||||
|
foreach ($relationColumns as $relationColumn => $targetColumn) {
|
||||||
|
$quotedTargetColumn = ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$targetColumn]))
|
||||||
|
? $targetColumn // Join columns cannot be quoted.
|
||||||
|
: $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
|
||||||
|
|
||||||
|
$conditions[] = $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply remaining inheritance restrictions
|
||||||
|
$discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($joinedDqlAlias));
|
||||||
|
|
||||||
|
if ($discrSql) {
|
||||||
|
$conditions[] = $discrSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the filters
|
||||||
|
$filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias);
|
||||||
|
|
||||||
|
if ($filterExpr) {
|
||||||
|
$conditions[] = $filterExpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: these should either be nested or all forced to be left joins (DDC-XXX)
|
||||||
|
if ($targetClass->isInheritanceTypeJoined()) {
|
||||||
|
$sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the indexes
|
||||||
|
if ($indexBy) {
|
||||||
|
// For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently.
|
||||||
|
$this->_rsm->addIndexBy(
|
||||||
|
$indexBy->simpleStateFieldPathExpression->identificationVariable,
|
||||||
|
$indexBy->simpleStateFieldPathExpression->field
|
||||||
|
);
|
||||||
|
} else if (isset($relation['indexBy'])) {
|
||||||
|
$this->_rsm->addIndexBy($joinedDqlAlias, $relation['indexBy']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sql;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down a FunctionNode AST node, thereby generating the appropriate SQL.
|
* Walks down a FunctionNode AST node, thereby generating the appropriate SQL.
|
||||||
*
|
*
|
||||||
@ -799,139 +954,27 @@ class SqlWalker implements TreeWalker
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
|
* Walks down a Join AST node and creates the corresponding SQL.
|
||||||
*
|
*
|
||||||
* @param JoinVariableDeclaration $joinVarDecl
|
|
||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
public function walkJoinVariableDeclaration($joinVarDecl)
|
public function walkJoin($join)
|
||||||
{
|
{
|
||||||
$join = $joinVarDecl->join;
|
|
||||||
$joinType = $join->joinType;
|
$joinType = $join->joinType;
|
||||||
|
$joinDeclaration = $join->joinAssociationDeclaration;
|
||||||
|
|
||||||
$sql = ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER)
|
$sql = ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER)
|
||||||
? ' LEFT JOIN '
|
? ' LEFT JOIN '
|
||||||
: ' INNER JOIN ';
|
: ' INNER JOIN ';
|
||||||
|
|
||||||
$joinPathExpr = $join->joinAssociationPathExpression;
|
switch (true) {
|
||||||
$joinedDqlAlias = $joinPathExpr->aliasIdentificationVariable;
|
case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\RangeVariableDeclaration):
|
||||||
|
$sql .= $this->walkRangeVariableDeclaration($joinDeclaration)
|
||||||
|
. ' ON (' . $this->walkConditionalExpression($join->conditionalExpression) . ')';
|
||||||
|
break;
|
||||||
|
|
||||||
if ($joinPathExpr instanceof \Doctrine\ORM\Query\AST\JoinClassPathExpression) {
|
case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\JoinAssociationDeclaration):
|
||||||
$targetClass = $this->_queryComponents[$joinedDqlAlias]['metadata'];
|
$sql .= $this->walkJoinAssociationDeclaration($joinDeclaration, $joinType);
|
||||||
|
|
||||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias);
|
|
||||||
$sql .= $targetClass->getQuotedTableName($this->_platform) . ' '
|
|
||||||
. $targetTableAlias;
|
|
||||||
|
|
||||||
$sql .= ' ON (' . $this->walkConditionalExpression($join->conditionalExpression) . ')';
|
|
||||||
} else {
|
|
||||||
|
|
||||||
$relation = $this->_queryComponents[$joinedDqlAlias]['relation'];
|
|
||||||
$targetClass = $this->_em->getClassMetadata($relation['targetEntity']);
|
|
||||||
$sourceClass = $this->_em->getClassMetadata($relation['sourceEntity']);
|
|
||||||
$targetTableName = $targetClass->getQuotedTableName($this->_platform);
|
|
||||||
|
|
||||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias);
|
|
||||||
$sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $joinPathExpr->identificationVariable);
|
|
||||||
|
|
||||||
// Ensure we got the owning side, since it has all mapping info
|
|
||||||
$assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation;
|
|
||||||
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true && (!$this->_query->getHint(self::HINT_DISTINCT) || isset($this->_selectedClasses[$joinedDqlAlias]))) {
|
|
||||||
if ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) {
|
|
||||||
throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot
|
|
||||||
// be the owning side and previously we ensured that $assoc is always the owning side of the associations.
|
|
||||||
// The owning side is necessary at this point because only it contains the JoinColumn information.
|
|
||||||
if ($assoc['type'] & ClassMetadata::TO_ONE) {
|
|
||||||
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
|
|
||||||
$first = true;
|
|
||||||
|
|
||||||
foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) {
|
|
||||||
if ( ! $first) $sql .= ' AND '; else $first = false;
|
|
||||||
|
|
||||||
if ($relation['isOwningSide']) {
|
|
||||||
if ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$targetColumn])) {
|
|
||||||
$quotedTargetColumn = $targetColumn; // Join columns cannot be quoted.
|
|
||||||
} else {
|
|
||||||
$quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
|
|
||||||
}
|
|
||||||
$sql .= $sourceTableAlias . '.' . $sourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn;
|
|
||||||
} else {
|
|
||||||
if ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$targetColumn])) {
|
|
||||||
$quotedTargetColumn = $targetColumn; // Join columns cannot be quoted.
|
|
||||||
} else {
|
|
||||||
$quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
|
|
||||||
}
|
|
||||||
$sql .= $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) {
|
|
||||||
// Join relation table
|
|
||||||
$joinTable = $assoc['joinTable'];
|
|
||||||
$joinTableAlias = $this->getSQLTableAlias($joinTable['name'], $joinedDqlAlias);
|
|
||||||
$sql .= $sourceClass->getQuotedJoinTableName($assoc, $this->_platform) . ' ' . $joinTableAlias . ' ON ';
|
|
||||||
|
|
||||||
$first = true;
|
|
||||||
if ($relation['isOwningSide']) {
|
|
||||||
foreach ($assoc['relationToSourceKeyColumns'] as $relationColumn => $sourceColumn) {
|
|
||||||
if ( ! $first) $sql .= ' AND '; else $first = false;
|
|
||||||
|
|
||||||
if ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$sourceColumn])) {
|
|
||||||
$quotedTargetColumn = $sourceColumn; // Join columns cannot be quoted.
|
|
||||||
} else {
|
|
||||||
$quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foreach ($assoc['relationToTargetKeyColumns'] as $relationColumn => $targetColumn) {
|
|
||||||
if ( ! $first) $sql .= ' AND '; else $first = false;
|
|
||||||
|
|
||||||
if ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$targetColumn])) {
|
|
||||||
$quotedTargetColumn = $targetColumn; // Join columns cannot be quoted.
|
|
||||||
} else {
|
|
||||||
$quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join target table
|
|
||||||
$sql .= ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) ? ' LEFT JOIN ' : ' INNER JOIN ';
|
|
||||||
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
|
|
||||||
|
|
||||||
$first = true;
|
|
||||||
if ($relation['isOwningSide']) {
|
|
||||||
foreach ($assoc['relationToTargetKeyColumns'] as $relationColumn => $targetColumn) {
|
|
||||||
if ( ! $first) $sql .= ' AND '; else $first = false;
|
|
||||||
|
|
||||||
if ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$targetColumn])) {
|
|
||||||
$quotedTargetColumn = $targetColumn; // Join columns cannot be quoted.
|
|
||||||
} else {
|
|
||||||
$quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foreach ($assoc['relationToSourceKeyColumns'] as $relationColumn => $sourceColumn) {
|
|
||||||
if ( ! $first) $sql .= ' AND '; else $first = false;
|
|
||||||
|
|
||||||
if ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$sourceColumn])) {
|
|
||||||
$quotedTargetColumn = $sourceColumn; // Join columns cannot be quoted.
|
|
||||||
} else {
|
|
||||||
$quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$sourceColumn], $this->_platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle WITH clause
|
// Handle WITH clause
|
||||||
if (($condExpr = $join->conditionalExpression) !== null) {
|
if (($condExpr = $join->conditionalExpression) !== null) {
|
||||||
@ -939,33 +982,7 @@ class SqlWalker implements TreeWalker
|
|||||||
// if only one ConditionalTerm is defined
|
// if only one ConditionalTerm is defined
|
||||||
$sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')';
|
$sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')';
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
|
||||||
// Apply the filters
|
|
||||||
if ($filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias)) {
|
|
||||||
$sql .= ' AND ' . $filterExpr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($joinVarDecl->indexBy) {
|
|
||||||
// For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently.
|
|
||||||
$this->_rsm->addIndexBy(
|
|
||||||
$joinVarDecl->indexBy->simpleStateFieldPathExpression->identificationVariable,
|
|
||||||
$joinVarDecl->indexBy->simpleStateFieldPathExpression->field
|
|
||||||
);
|
|
||||||
} else if (isset($relation['indexBy'])) {
|
|
||||||
$this->_rsm->addIndexBy($joinedDqlAlias, $relation['indexBy']);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($joinedDqlAlias));
|
|
||||||
|
|
||||||
if ($discrSql) {
|
|
||||||
$sql .= ' AND ' . $discrSql;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: these should either be nested or all forced to be left joins (DDC-XXX)
|
|
||||||
if ($targetClass->isInheritanceTypeJoined()) {
|
|
||||||
$sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sql;
|
return $sql;
|
||||||
@ -1308,23 +1325,10 @@ class SqlWalker implements TreeWalker
|
|||||||
$sqlParts = array ();
|
$sqlParts = array ();
|
||||||
|
|
||||||
foreach ($identificationVarDecls as $subselectIdVarDecl) {
|
foreach ($identificationVarDecls as $subselectIdVarDecl) {
|
||||||
$sql = '';
|
$sql = $this->walkRangeVariableDeclaration($subselectIdVarDecl->rangeVariableDeclaration);
|
||||||
|
|
||||||
$rangeDecl = $subselectIdVarDecl->rangeVariableDeclaration;
|
foreach ($subselectIdVarDecl->joins as $join) {
|
||||||
$dqlAlias = $rangeDecl->aliasIdentificationVariable;
|
$sql .= $this->walkJoin($join);
|
||||||
|
|
||||||
$class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName);
|
|
||||||
$sql .= $class->getQuotedTableName($this->_platform) . ' '
|
|
||||||
. $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
|
||||||
|
|
||||||
$this->_rootAliases[] = $dqlAlias;
|
|
||||||
|
|
||||||
if ($class->isInheritanceTypeJoined()) {
|
|
||||||
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($subselectIdVarDecl->joinVariableDeclarations as $joinVarDecl) {
|
|
||||||
$sql .= $this->walkJoinVariableDeclaration($joinVarDecl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sqlParts[] = $this->_platform->appendLockHint($sql, $this->_query->getHint(Query::HINT_LOCK_MODE));
|
$sqlParts[] = $this->_platform->appendLockHint($sql, $this->_query->getHint(Query::HINT_LOCK_MODE));
|
||||||
|
@ -91,12 +91,12 @@ interface TreeWalker
|
|||||||
function walkHavingClause($havingClause);
|
function walkHavingClause($havingClause);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
|
* Walks down a Join AST node and creates the corresponding SQL.
|
||||||
*
|
*
|
||||||
* @param JoinVariableDeclaration $joinVarDecl
|
* @param Join $joinVarDecl
|
||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
function walkJoinVariableDeclaration($joinVarDecl);
|
function walkJoin($join);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down a SelectExpression AST node and generates the corresponding SQL.
|
* Walks down a SelectExpression AST node and generates the corresponding SQL.
|
||||||
|
@ -125,12 +125,12 @@ abstract class TreeWalkerAdapter implements TreeWalker
|
|||||||
public function walkHavingClause($havingClause) {}
|
public function walkHavingClause($havingClause) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
|
* Walks down a Join AST node and creates the corresponding SQL.
|
||||||
*
|
*
|
||||||
* @param JoinVariableDeclaration $joinVarDecl
|
* @param Join $join
|
||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
public function walkJoinVariableDeclaration($joinVarDecl) {}
|
public function walkJoin($join) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down a SelectExpression AST node and generates the corresponding SQL.
|
* Walks down a SelectExpression AST node and generates the corresponding SQL.
|
||||||
|
@ -148,15 +148,15 @@ class TreeWalkerChain implements TreeWalker
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
|
* Walks down a Join AST node and creates the corresponding SQL.
|
||||||
*
|
*
|
||||||
* @param JoinVariableDeclaration $joinVarDecl
|
* @param Join $join
|
||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
public function walkJoinVariableDeclaration($joinVarDecl)
|
public function walkJoin($join)
|
||||||
{
|
{
|
||||||
foreach ($this->_walkers as $walker) {
|
foreach ($this->_walkers as $walker) {
|
||||||
$walker->walkJoinVariableDeclaration($joinVarDecl);
|
$walker->walkJoin($join);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +206,11 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
$this->assertValidDQL('SELECT u.name, a.topic, p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a LEFT JOIN u.phonenumbers p');
|
$this->assertValidDQL('SELECT u.name, a.topic, p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a LEFT JOIN u.phonenumbers p');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testJoinClassPath()
|
||||||
|
{
|
||||||
|
$this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN Doctrine\Tests\Models\CMS\CmsArticle a WITH a.user = u.id');
|
||||||
|
}
|
||||||
|
|
||||||
public function testOrderBySingleColumn()
|
public function testOrderBySingleColumn()
|
||||||
{
|
{
|
||||||
$this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.name');
|
$this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.name');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user