Skip to content

Instantly share code, notes, and snippets.

@doctrinebot
Created December 13, 2015 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doctrinebot/044a2dc627a11e5c3a9e to your computer and use it in GitHub Desktop.
Save doctrinebot/044a2dc627a11e5c3a9e to your computer and use it in GitHub Desktop.
Attachments to Doctrine Jira Issue DDC-736 - https://github.com/doctrine/doctrine2/issues/5249
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\Models\ECommerce\ECommerceCart;
use Doctrine\Tests\Models\ECommerce\ECommerceCustomer;
require_once __DIR__ . '/../../../TestInit.php';
class DDC736Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
$this->useModelSet('ecommerce');
parent::setUp();
}
/**
* @group DDC-736
*/
public function testFetchJoinInitializesPreviouslyUninitializedCollectionOfManagedEntity()
{
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$cust = new ECommerceCustomer;
$cust->setName('roman');
$cart = new ECommerceCart;
$cart->setPayment('cash');
$cart->setCustomer($cust);
$this->_em->persist($cust);
$this->_em->persist($cart);
$this->_em->flush();
$this->_em->clear();
$cart2 = $this->_em->createQuery("select c, ca from Doctrine\Tests\Models\ECommerce\ECommerceCart ca join ca.customer c")
->getSingleResult(/*\Doctrine\ORM\Query::HYDRATE_ARRAY*/);
$this->assertTrue($cart2 instanceof ECommerceCart);
$this->assertFalse($cart2->getCustomer() instanceof \Doctrine\ORM\Proxy\Proxy);
$this->assertTrue($cart2->getCustomer() instanceof ECommerceCustomer);
}
}
diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php
index 3d3fb5f..c2ee213 100644
--- a/lib/Doctrine/ORM/Query/Parser.php
+++ b/lib/Doctrine/ORM/Query/Parser.php
@@ -126,6 +126,16 @@ class Parser
private $_customOutputWalker;
/**
+ * @var array
+ */
+ private $_identVariableOrder = array();
+
+ /**
+ * @var array
+ */
+ private $_identVariableExpressions = array();
+
+ /**
* Creates a new query parser object.
*
* @param Query $query The Query to parse.
@@ -297,6 +307,19 @@ class Parser
}
}
+ // fix order of identification variables
+ if ( count($this->_identVariableExpressions) > 1) {
+ $n = count($this->_identVariableOrder);
+ for ($i = 0; $i < $n; $i++) {
+ if (isset($this->_identVariableExpressions[$this->_identVariableOrder[$i]])) {
+ $expr = $this->_identVariableExpressions[$this->_identVariableOrder[$i]];
+ $key = array_search($expr, $AST->selectClause->selectExpressions);
+ unset($AST->selectClause->selectExpressions[$key]);
+ $AST->selectClause->selectExpressions[] = $expr;
+ }
+ }
+ }
+
if ($this->_customOutputWalker) {
$outputWalker = new $this->_customOutputWalker(
$this->_query, $this->_parserResult, $this->_queryComponents
@@ -1419,6 +1442,7 @@ class Parser
$token = $this->_lexer->lookahead;
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
+ $this->_identVariableOrder[] = $aliasIdentificationVariable;
$classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
// Building queryComponent
@@ -1509,6 +1533,7 @@ class Parser
$token = $this->_lexer->lookahead;
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
+ $this->_identVariableOrder[] = $aliasIdentificationVariable;
// Verify that the association exists.
$parentClass = $this->_queryComponents[$joinPathExpression->identificationVariable]['metadata'];
@@ -1628,6 +1653,7 @@ class Parser
public function SelectExpression()
{
$expression = null;
+ $identVariable = null;
$fieldAliasIdentificationVariable = null;
$peek = $this->_lexer->glimpse();
@@ -1639,7 +1665,7 @@ class Parser
$expression = $this->ScalarExpression();
} else {
$supportsAlias = false;
- $expression = $this->IdentificationVariable();
+ $expression = $identVariable = $this->IdentificationVariable();
}
} else if ($this->_lexer->lookahead['value'] == '(') {
if ($peek['type'] == Lexer::T_SELECT) {
@@ -1666,6 +1692,7 @@ class Parser
} else if ($this->_lexer->lookahead['type'] == Lexer::T_PARTIAL) {
$supportsAlias = false;
$expression = $this->PartialObjectExpression();
+ $identVariable = $expression->identificationVariable;
} else if ($this->_lexer->lookahead['type'] == Lexer::T_INTEGER ||
$this->_lexer->lookahead['type'] == Lexer::T_FLOAT) {
// Shortcut: ScalarExpression => SimpleArithmeticExpression
@@ -1694,7 +1721,11 @@ class Parser
}
}
- return new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
+ $expr = new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
+ if (!$supportsAlias) {
+ $this->_identVariableExpressions[$identVariable] = $expr;
+ }
+ return $expr;
}
/**
diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php
index 3d3fb5f..9131f53 100644
--- a/lib/Doctrine/ORM/Query/Parser.php
+++ b/lib/Doctrine/ORM/Query/Parser.php
@@ -126,6 +126,11 @@ class Parser
private $_customOutputWalker;
/**
+ * @var array
+ */
+ private $_identVariableExpressions = array();
+
+ /**
* Creates a new query parser object.
*
* @param Query $query The Query to parse.
@@ -297,6 +302,21 @@ class Parser
}
}
+ // Fix order of identification variables.
+ // They have to appear in the select clause in the same order as the
+ // declarations (from ... x join ... y join ... z ...) appear in the query
+ // as the hydration process relies on that order for proper operation.
+ if (count($this->_identVariableExpressions) > 1) {
+ foreach ($this->_queryComponents as $dqlAlias => $comp) {
+ if (isset($this->_identVariableExpressions[$dqlAlias])) {
+ $expr = $this->_identVariableExpressions[$dqlAlias];
+ $key = array_search($expr, $AST->selectClause->selectExpressions);
+ unset($AST->selectClause->selectExpressions[$key]);
+ $AST->selectClause->selectExpressions[] = $expr;
+ }
+ }
+ }
+
if ($this->_customOutputWalker) {
$outputWalker = new $this->_customOutputWalker(
$this->_query, $this->_parserResult, $this->_queryComponents
@@ -1628,6 +1648,7 @@ class Parser
public function SelectExpression()
{
$expression = null;
+ $identVariable = null;
$fieldAliasIdentificationVariable = null;
$peek = $this->_lexer->glimpse();
@@ -1639,7 +1660,7 @@ class Parser
$expression = $this->ScalarExpression();
} else {
$supportsAlias = false;
- $expression = $this->IdentificationVariable();
+ $expression = $identVariable = $this->IdentificationVariable();
}
} else if ($this->_lexer->lookahead['value'] == '(') {
if ($peek['type'] == Lexer::T_SELECT) {
@@ -1666,6 +1687,7 @@ class Parser
} else if ($this->_lexer->lookahead['type'] == Lexer::T_PARTIAL) {
$supportsAlias = false;
$expression = $this->PartialObjectExpression();
+ $identVariable = $expression->identificationVariable;
} else if ($this->_lexer->lookahead['type'] == Lexer::T_INTEGER ||
$this->_lexer->lookahead['type'] == Lexer::T_FLOAT) {
// Shortcut: ScalarExpression => SimpleArithmeticExpression
@@ -1694,7 +1716,11 @@ class Parser
}
}
- return new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
+ $expr = new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
+ if (!$supportsAlias) {
+ $this->_identVariableExpressions[$identVariable] = $expr;
+ }
+ return $expr;
}
/**
diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php
index e43965e..979427a 100644
--- a/lib/Doctrine/ORM/Query/SqlWalker.php
+++ b/lib/Doctrine/ORM/Query/SqlWalker.php
@@ -382,7 +382,7 @@ class SqlWalker implements TreeWalker
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
$sql .= " " . $this->_platform->getWriteLockSQL();
} else if ($lockMode == LockMode::OPTIMISTIC) {
- foreach ($this->_selectedClasses AS $class) {
+ foreach ($this->_selectedClasses as $class) {
if ( ! $class->isVersioned) {
throw \Doctrine\ORM\OptimisticLockException::lockFailed();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment