Made DQL and EBNF in sync.
This commit is contained in:
parent
a3f95d919b
commit
6a8ee87268
@ -1440,6 +1440,12 @@ Identifiers
|
||||
/* identifier that must be a class name (the "User" of "FROM User u") */
|
||||
AbstractSchemaName ::= identifier
|
||||
|
||||
/* Alias ResultVariable declaration (the "total" of "COUNT(*) AS total") */
|
||||
AliasResultVariable = identifier
|
||||
|
||||
/* ResultVariable identifier usage of mapped field aliases (the "total" of "COUNT(*) AS total") */
|
||||
ResultVariable = identifier
|
||||
|
||||
/* identifier that must be a field (the "name" of "u.name") */
|
||||
/* This is responsible to know if the field exists in Object, no matter if it's a relation or a simple field */
|
||||
FieldIdentificationVariable ::= identifier
|
||||
@ -1450,19 +1456,13 @@ Identifiers
|
||||
/* identifier that must be a single-valued association field (to-one) (the "Group" of "u.Group") */
|
||||
SingleValuedAssociationField ::= FieldIdentificationVariable
|
||||
|
||||
/* identifier that must be an embedded class state field (for the future) */
|
||||
/* identifier that must be an embedded class state field */
|
||||
EmbeddedClassStateField ::= FieldIdentificationVariable
|
||||
|
||||
/* identifier that must be a simple state field (name, email, ...) (the "name" of "u.name") */
|
||||
/* The difference between this and FieldIdentificationVariable is only semantical, because it points to a single field (not mapping to a relation) */
|
||||
SimpleStateField ::= FieldIdentificationVariable
|
||||
|
||||
/* Alias ResultVariable declaration (the "total" of "COUNT(*) AS total") */
|
||||
AliasResultVariable = identifier
|
||||
|
||||
/* ResultVariable identifier usage of mapped field aliases (the "total" of "COUNT(*) AS total") */
|
||||
ResultVariable = identifier
|
||||
|
||||
Path Expressions
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1521,11 +1521,11 @@ From, Join and Index by
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
|
||||
SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)
|
||||
JoinVariableDeclaration ::= Join [IndexBy]
|
||||
IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {Join}*
|
||||
SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration
|
||||
RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
|
||||
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression ["AS"] AliasIdentificationVariable ["WITH" ConditionalExpression]
|
||||
JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
|
||||
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" (JoinAssociationDeclaration | RangeVariableDeclaration) ["WITH" ConditionalExpression]
|
||||
IndexBy ::= "INDEX" "BY" StateFieldPathExpression
|
||||
|
||||
Select Expressions
|
||||
@ -1533,10 +1533,12 @@ Select Expressions
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
SelectExpression ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
SelectExpression ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
SimpleSelectExpression ::= (StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
|
||||
PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
|
||||
PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
|
||||
NewObjectExpression ::= "NEW" IdentificationVariable "(" NewObjectArg {"," NewObjectArg}* ")"
|
||||
NewObjectArg ::= ScalarExpression | "(" Subselect ")"
|
||||
|
||||
Conditional Expressions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
61
lib/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php
Normal file
61
lib/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/*
|
||||
* 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 MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* JoinVariableDeclaration ::= Join [IndexBy]
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.5
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
*/
|
||||
class JoinVariableDeclaration extends Node
|
||||
{
|
||||
/**
|
||||
* @var Join
|
||||
*/
|
||||
public $join;
|
||||
|
||||
/**
|
||||
* @var IndexBy|null
|
||||
*/
|
||||
public $indexBy;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Join $join
|
||||
* @param IndexBy|null $indexBy
|
||||
*/
|
||||
public function __construct($join, $indexBy)
|
||||
{
|
||||
$this->join = $join;
|
||||
$this->indexBy = $indexBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkJoinVariableDeclaration($this);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/*
|
||||
* 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 MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SubselectIdentificationVariableDeclaration ::= AssociationPathExpression ["AS"] AliasIdentificationVariable
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
*/
|
||||
class SubselectIdentificationVariableDeclaration
|
||||
{
|
||||
/**
|
||||
* @var PathExpression
|
||||
*/
|
||||
public $associationPathExpression;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $aliasIdentificationVariable;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param PathExpression $associationPathExpression
|
||||
* @param string $aliasIdentificationVariable
|
||||
*/
|
||||
public function __construct($associationPathExpression, $aliasIdentificationVariable)
|
||||
{
|
||||
$this->associationPathExpression = $associationPathExpression;
|
||||
$this->aliasIdentificationVariable = $aliasIdentificationVariable;
|
||||
}
|
||||
}
|
@ -1049,7 +1049,7 @@ class Parser
|
||||
* Parses an arbitrary path expression and defers semantical validation
|
||||
* based on expected types.
|
||||
*
|
||||
* PathExpression ::= IdentificationVariable "." identifier [ ("." identifier)* ]
|
||||
* PathExpression ::= IdentificationVariable {"." identifier}*
|
||||
*
|
||||
* @param integer $expectedTypes
|
||||
*
|
||||
@ -1553,13 +1553,14 @@ class Parser
|
||||
*/
|
||||
public function IdentificationVariableDeclaration()
|
||||
{
|
||||
$joins = array();
|
||||
$rangeVariableDeclaration = $this->RangeVariableDeclaration();
|
||||
$indexBy = $this->lexer->isNextToken(Lexer::T_INDEX)
|
||||
? $this->IndexBy()
|
||||
: null;
|
||||
|
||||
$rangeVariableDeclaration->isRoot = true;
|
||||
|
||||
$indexBy = $this->lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
|
||||
$joins = array();
|
||||
|
||||
while (
|
||||
$this->lexer->isNextToken(Lexer::T_LEFT) ||
|
||||
$this->lexer->isNextToken(Lexer::T_INNER) ||
|
||||
@ -1574,24 +1575,59 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration
|
||||
*
|
||||
* {@internal WARNING: Solution is harder than a bare implementation.
|
||||
* Desired EBNF support:
|
||||
*
|
||||
* SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)
|
||||
*
|
||||
* It demands that entire SQL generation to become programmatical. This is
|
||||
* needed because association based subselect requires "WHERE" conditional
|
||||
* expressions to be injected, but there is no scope to do that. Only scope
|
||||
* accessible is "FROM", prohibiting an easy implementation without larger
|
||||
* changes.}
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\AST\SubselectIdentificationVariableDeclaration |
|
||||
* \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
|
||||
*/
|
||||
public function SubselectIdentificationVariableDeclaration()
|
||||
{
|
||||
$this->lexer->glimpse();
|
||||
/*
|
||||
NOT YET IMPLEMENTED!
|
||||
|
||||
/* NOT YET IMPLEMENTED!
|
||||
$glimpse = $this->lexer->glimpse();
|
||||
|
||||
if ($glimpse['type'] == Lexer::T_DOT) {
|
||||
$subselectIdVarDecl = new AST\SubselectIdentificationVariableDeclaration();
|
||||
$subselectIdVarDecl->associationPathExpression = $this->AssociationPathExpression();
|
||||
$this->match(Lexer::T_AS);
|
||||
$subselectIdVarDecl->aliasIdentificationVariable = $this->AliasIdentificationVariable();
|
||||
$associationPathExpression = $this->AssociationPathExpression();
|
||||
|
||||
return $subselectIdVarDecl;
|
||||
if ($this->lexer->isNextToken(Lexer::T_AS)) {
|
||||
$this->match(Lexer::T_AS);
|
||||
}
|
||||
|
||||
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
|
||||
$identificationVariable = $associationPathExpression->identificationVariable;
|
||||
$field = $associationPathExpression->associationField;
|
||||
|
||||
$class = $this->queryComponents[$identificationVariable]['metadata'];
|
||||
$targetClass = $this->em->getClassMetadata($class->associationMappings[$field]['targetEntity']);
|
||||
|
||||
// Building queryComponent
|
||||
$joinQueryComponent = array(
|
||||
'metadata' => $targetClass,
|
||||
'parent' => $identificationVariable,
|
||||
'relation' => $class->getAssociationMapping($field),
|
||||
'map' => null,
|
||||
'nestingLevel' => $this->nestingLevel,
|
||||
'token' => $this->lexer->lookahead
|
||||
);
|
||||
|
||||
$this->queryComponents[$aliasIdentificationVariable] = $joinQueryComponent;
|
||||
|
||||
return new AST\SubselectIdentificationVariableDeclaration(
|
||||
$associationPathExpression, $aliasIdentificationVariable
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
@ -1819,7 +1855,7 @@ class Parser
|
||||
{
|
||||
$token = $this->lexer->lookahead;
|
||||
$peek = $this->lexer->glimpse();
|
||||
|
||||
|
||||
if ($token['type'] === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT) {
|
||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$expression = $this->Subselect();
|
||||
@ -1827,7 +1863,7 @@ class Parser
|
||||
|
||||
return $expression;
|
||||
}
|
||||
|
||||
|
||||
return $this->ScalarExpression();
|
||||
}
|
||||
|
||||
@ -2097,7 +2133,7 @@ class Parser
|
||||
/**
|
||||
* SelectExpression ::= (
|
||||
* IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration |
|
||||
* PartialObjectExpression | "(" Subselect ")" | CaseExpression
|
||||
* PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression
|
||||
* ) [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\AST\SelectExpression
|
||||
@ -3160,7 +3196,7 @@ class Parser
|
||||
case $this->lexer->isNextToken(Lexer::T_COALESCE):
|
||||
$expr = $this->CoalesceExpression();
|
||||
break;
|
||||
|
||||
|
||||
case $this->isAggregateFunction($this->lexer->lookahead['type']):
|
||||
$expr = $this->AggregateExpression();
|
||||
break;
|
||||
@ -3346,7 +3382,10 @@ class Parser
|
||||
* "ABS" "(" SimpleArithmeticExpression ")" |
|
||||
* "SQRT" "(" SimpleArithmeticExpression ")" |
|
||||
* "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
|
||||
* "SIZE" "(" CollectionValuedPathExpression ")"
|
||||
* "SIZE" "(" CollectionValuedPathExpression ")" |
|
||||
* "DATE_DIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")" |
|
||||
* "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")" |
|
||||
* "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
|
||||
*/
|
||||
@ -3377,7 +3416,12 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
* FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"
|
||||
* FunctionsReturningDateTime ::=
|
||||
* "CURRENT_DATE" |
|
||||
* "CURRENT_TIME" |
|
||||
* "CURRENT_TIMESTAMP" |
|
||||
* "DATE_ADD" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")" |
|
||||
* "DATE_SUB" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")"
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
|
||||
*/
|
||||
|
@ -803,32 +803,56 @@ class SqlWalker implements TreeWalker
|
||||
$sqlParts = array();
|
||||
|
||||
foreach ($identificationVarDecls as $identificationVariableDecl) {
|
||||
$sql = $this->walkRangeVariableDeclaration($identificationVariableDecl->rangeVariableDeclaration);
|
||||
|
||||
foreach ($identificationVariableDecl->joins as $join) {
|
||||
$sql .= $this->walkJoin($join);
|
||||
}
|
||||
|
||||
if ($identificationVariableDecl->indexBy) {
|
||||
$alias = $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->identificationVariable;
|
||||
$field = $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->field;
|
||||
|
||||
if (isset($this->scalarFields[$alias][$field])) {
|
||||
$this->rsm->addIndexByScalar($this->scalarFields[$alias][$field]);
|
||||
} else {
|
||||
$this->rsm->addIndexBy(
|
||||
$identificationVariableDecl->indexBy->simpleStateFieldPathExpression->identificationVariable,
|
||||
$identificationVariableDecl->indexBy->simpleStateFieldPathExpression->field
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$sqlParts[] = $sql;
|
||||
$sqlParts[] = $this->walkIdentificationVariableDeclaration($identificationVariableDecl);
|
||||
}
|
||||
|
||||
return ' FROM ' . implode(', ', $sqlParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a IdentificationVariableDeclaration AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param AST\IdentificationVariableDeclaration $identificationVariableDecl
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function walkIdentificationVariableDeclaration($identificationVariableDecl)
|
||||
{
|
||||
$sql = $this->walkRangeVariableDeclaration($identificationVariableDecl->rangeVariableDeclaration);
|
||||
|
||||
if ($identificationVariableDecl->indexBy) {
|
||||
$this->walkIndexBy($identificationVariableDecl->indexBy);
|
||||
}
|
||||
|
||||
foreach ($identificationVariableDecl->joins as $join) {
|
||||
$sql .= $this->walkJoin($join);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a IndexBy AST node.
|
||||
*
|
||||
* @param AST\IndexBy $indexBy
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function walkIndexBy($indexBy)
|
||||
{
|
||||
$pathExpression = $indexBy->simpleStateFieldPathExpression;
|
||||
$alias = $pathExpression->identificationVariable;
|
||||
$field = $pathExpression->field;
|
||||
|
||||
if (isset($this->scalarFields[$alias][$field])) {
|
||||
$this->rsm->addIndexByScalar($this->scalarFields[$alias][$field]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->rsm->addIndexBy($alias, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a RangeVariableDeclaration AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
@ -1017,10 +1041,7 @@ class SqlWalker implements TreeWalker
|
||||
// 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
|
||||
);
|
||||
$this->walkIndexBy($indexBy);
|
||||
} else if (isset($relation['indexBy'])) {
|
||||
$this->rsm->addIndexBy($joinedDqlAlias, $relation['indexBy']);
|
||||
}
|
||||
@ -1456,16 +1477,10 @@ class SqlWalker implements TreeWalker
|
||||
public function walkSubselectFromClause($subselectFromClause)
|
||||
{
|
||||
$identificationVarDecls = $subselectFromClause->identificationVariableDeclarations;
|
||||
$sqlParts = array ();
|
||||
$sqlParts = array ();
|
||||
|
||||
foreach ($identificationVarDecls as $subselectIdVarDecl) {
|
||||
$sql = $this->walkRangeVariableDeclaration($subselectIdVarDecl->rangeVariableDeclaration);
|
||||
|
||||
foreach ($subselectIdVarDecl->joins as $join) {
|
||||
$sql .= $this->walkJoin($join);
|
||||
}
|
||||
|
||||
$sqlParts[] = $sql;
|
||||
$sqlParts[] = $this->walkIdentificationVariableDeclaration($subselectIdVarDecl);
|
||||
}
|
||||
|
||||
return ' FROM ' . implode(', ', $sqlParts);
|
||||
@ -1520,7 +1535,7 @@ class SqlWalker implements TreeWalker
|
||||
$qComp = $this->queryComponents[$dqlAlias];
|
||||
$class = $qComp['metadata'];
|
||||
$fieldType = $class->getTypeOfField($fieldName);
|
||||
|
||||
|
||||
$sqlSelectExpressions[] = trim($e->dispatch($this)) . ' AS ' . $columnAlias;
|
||||
break;
|
||||
|
||||
|
@ -74,37 +74,40 @@ class CustomTreeWalkerJoin extends Query\TreeWalkerAdapter
|
||||
public function walkSelectStatement(Query\AST\SelectStatement $selectStatement)
|
||||
{
|
||||
foreach ($selectStatement->fromClause->identificationVariableDeclarations as $identificationVariableDeclaration) {
|
||||
if ($identificationVariableDeclaration->rangeVariableDeclaration->abstractSchemaName == 'Doctrine\Tests\Models\CMS\CmsUser') {
|
||||
$identificationVariableDeclaration->joins[] = new Query\AST\Join(
|
||||
Query\AST\Join::JOIN_TYPE_LEFT,
|
||||
new Query\AST\JoinAssociationDeclaration(
|
||||
new Query\AST\JoinAssociationPathExpression(
|
||||
$identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable,
|
||||
'address'
|
||||
),
|
||||
$identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a',
|
||||
null
|
||||
)
|
||||
);
|
||||
$selectStatement->selectClause->selectExpressions[] =
|
||||
new Query\AST\SelectExpression(
|
||||
$identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a',
|
||||
null,
|
||||
false
|
||||
);
|
||||
$meta1 = $this->_getQuery()->getEntityManager()->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$meta = $this->_getQuery()->getEntityManager()->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
$this->setQueryComponent($identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a',
|
||||
array(
|
||||
'metadata' => $meta,
|
||||
'parent' => $identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable,
|
||||
'relation' => $meta1->getAssociationMapping('address'),
|
||||
'map' => null,
|
||||
'nestingLevel' => 0,
|
||||
'token' => null
|
||||
)
|
||||
);
|
||||
$rangeVariableDecl = $identificationVariableDeclaration->rangeVariableDeclaration;
|
||||
|
||||
if ($rangeVariableDecl->abstractSchemaName !== 'Doctrine\Tests\Models\CMS\CmsUser') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->modifySelectStatement($selectStatement, $identificationVariableDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
private function modifySelectStatement(Query\AST\SelectStatement $selectStatement, $identificationVariableDecl)
|
||||
{
|
||||
$rangeVariableDecl = $identificationVariableDecl->rangeVariableDeclaration;
|
||||
$joinAssocPathExpression = new Query\AST\JoinAssociationPathExpression($rangeVariableDecl->aliasIdentificationVariable, 'address');
|
||||
$joinAssocDeclaration = new Query\AST\JoinAssociationDeclaration($joinAssocPathExpression, $rangeVariableDecl->aliasIdentificationVariable . 'a', null);
|
||||
$join = new Query\AST\Join(Query\AST\Join::JOIN_TYPE_LEFT, $joinAssocDeclaration);
|
||||
$selectExpression = new Query\AST\SelectExpression($rangeVariableDecl->aliasIdentificationVariable . 'a', null, false);
|
||||
|
||||
$identificationVariableDecl->joins[] = $join;
|
||||
$selectStatement->selectClause->selectExpressions[] = $selectExpression;
|
||||
|
||||
$entityManager = $this->_getQuery()->getEntityManager();
|
||||
$userMetadata = $entityManager->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$addressMetadata = $entityManager->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
|
||||
$this->setQueryComponent($rangeVariableDecl->aliasIdentificationVariable . 'a',
|
||||
array(
|
||||
'metadata' => $addressMetadata,
|
||||
'parent' => $rangeVariableDecl->aliasIdentificationVariable,
|
||||
'relation' => $userMetadata->getAssociationMapping('address'),
|
||||
'map' => null,
|
||||
'nestingLevel' => 0,
|
||||
'token' => null,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -198,37 +198,40 @@ class CustomTreeWalkerJoin extends Query\TreeWalkerAdapter
|
||||
public function walkSelectStatement(Query\AST\SelectStatement $selectStatement)
|
||||
{
|
||||
foreach ($selectStatement->fromClause->identificationVariableDeclarations as $identificationVariableDeclaration) {
|
||||
if ($identificationVariableDeclaration->rangeVariableDeclaration->abstractSchemaName == 'Doctrine\Tests\Models\CMS\CmsUser') {
|
||||
$identificationVariableDeclaration->joins[] = new Query\AST\Join(
|
||||
Query\AST\Join::JOIN_TYPE_LEFT,
|
||||
new Query\AST\JoinAssociationDeclaration(
|
||||
new Query\AST\JoinAssociationPathExpression(
|
||||
$identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable,
|
||||
'address'
|
||||
),
|
||||
$identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a',
|
||||
null
|
||||
)
|
||||
);
|
||||
$selectStatement->selectClause->selectExpressions[] =
|
||||
new Query\AST\SelectExpression(
|
||||
$identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a',
|
||||
null,
|
||||
false
|
||||
);
|
||||
$meta1 = $this->_getQuery()->getEntityManager()->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$meta = $this->_getQuery()->getEntityManager()->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
$this->setQueryComponent($identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable . 'a',
|
||||
array(
|
||||
'metadata' => $meta,
|
||||
'parent' => $identificationVariableDeclaration->rangeVariableDeclaration->aliasIdentificationVariable,
|
||||
'relation' => $meta1->getAssociationMapping('address'),
|
||||
'map' => null,
|
||||
'nestingLevel' => 0,
|
||||
'token' => null
|
||||
)
|
||||
);
|
||||
$rangeVariableDecl = $identificationVariableDeclaration->rangeVariableDeclaration;
|
||||
|
||||
if ($rangeVariableDecl->abstractSchemaName !== 'Doctrine\Tests\Models\CMS\CmsUser') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->modifySelectStatement($selectStatement, $identificationVariableDeclaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function modifySelectStatement(Query\AST\SelectStatement $selectStatement, $identificationVariableDecl)
|
||||
{
|
||||
$rangeVariableDecl = $identificationVariableDecl->rangeVariableDeclaration;
|
||||
$joinAssocPathExpression = new Query\AST\JoinAssociationPathExpression($rangeVariableDecl->aliasIdentificationVariable, 'address');
|
||||
$joinAssocDeclaration = new Query\AST\JoinAssociationDeclaration($joinAssocPathExpression, $rangeVariableDecl->aliasIdentificationVariable . 'a', null);
|
||||
$join = new Query\AST\Join(Query\AST\Join::JOIN_TYPE_LEFT, $joinAssocDeclaration);
|
||||
$selectExpression = new Query\AST\SelectExpression($rangeVariableDecl->aliasIdentificationVariable . 'a', null, false);
|
||||
|
||||
$identificationVariableDecl->joins[] = $join;
|
||||
$selectStatement->selectClause->selectExpressions[] = $selectExpression;
|
||||
|
||||
$entityManager = $this->_getQuery()->getEntityManager();
|
||||
$userMetadata = $entityManager->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$addressMetadata = $entityManager->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
|
||||
$this->setQueryComponent($rangeVariableDecl->aliasIdentificationVariable . 'a',
|
||||
array(
|
||||
'metadata' => $addressMetadata,
|
||||
'parent' => $rangeVariableDecl->aliasIdentificationVariable,
|
||||
'relation' => $userMetadata->getAssociationMapping('address'),
|
||||
'map' => null,
|
||||
'nestingLevel' => 0,
|
||||
'token' => null,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user