1
0
mirror of synced 2025-01-31 04:21:44 +03:00

[DDC-3108] Fix regression introduced in DDC-2764 where join aliases were no longer accessible in Criteria expressions

This commit is contained in:
Kiel Goodman 2014-12-06 14:40:03 +00:00 committed by Marco Pivetta
parent 6ba5211310
commit 918d2910d9
4 changed files with 165 additions and 18 deletions

View File

@ -45,9 +45,9 @@ class QueryExpressionVisitor extends ExpressionVisitor
);
/**
* @var string
* @var array
*/
private $rootAlias;
private $queryAliases;
/**
* @var Expr
@ -62,11 +62,11 @@ class QueryExpressionVisitor extends ExpressionVisitor
/**
* Constructor
*
* @param string $rootAlias
* @param string $queryAliases
*/
public function __construct($rootAlias)
public function __construct($queryAliases)
{
$this->rootAlias = $rootAlias;
$this->queryAliases = $queryAliases;
$this->expr = new Expr();
}
@ -131,7 +131,25 @@ class QueryExpressionVisitor extends ExpressionVisitor
*/
public function walkComparison(Comparison $comparison)
{
$parameterName = str_replace('.', '_', $comparison->getField());
if ( ! isset($this->queryAliases[0])) {
throw new \RuntimeException('No aliases are set before invoking walkComparison().');
}
$field = $comparison->getField();
$hasValidAlias = false;
foreach($this->queryAliases as $alias) {
if(strpos($field . '.', $alias . '.') === 0) {
$hasValidAlias = true;
break;
}
}
$parameterName = str_replace('.', '_', $field);
if(!$hasValidAlias) {
$field = $this->queryAliases[0] . '.' . $field;
}
foreach($this->parameters as $parameter) {
if($parameter->getName() === $parameterName) {
@ -146,38 +164,38 @@ class QueryExpressionVisitor extends ExpressionVisitor
switch ($comparison->getOperator()) {
case Comparison::IN:
$this->parameters[] = $parameter;
return $this->expr->in($this->rootAlias . '.' . $comparison->getField(), $placeholder);
return $this->expr->in($field, $placeholder);
case Comparison::NIN:
$this->parameters[] = $parameter;
return $this->expr->notIn($this->rootAlias . '.' . $comparison->getField(), $placeholder);
return $this->expr->notIn($field, $placeholder);
case Comparison::EQ:
case Comparison::IS:
if ($this->walkValue($comparison->getValue()) === null) {
return $this->expr->isNull($this->rootAlias . '.' . $comparison->getField());
return $this->expr->isNull($field);
}
$this->parameters[] = $parameter;
return $this->expr->eq($this->rootAlias . '.' . $comparison->getField(), $placeholder);
return $this->expr->eq($field, $placeholder);
case Comparison::NEQ:
if ($this->walkValue($comparison->getValue()) === null) {
return $this->expr->isNotNull($this->rootAlias . '.' . $comparison->getField());
return $this->expr->isNotNull($field);
}
$this->parameters[] = $parameter;
return $this->expr->neq($this->rootAlias . '.' . $comparison->getField(), $placeholder);
return $this->expr->neq($field, $placeholder);
case Comparison::CONTAINS:
$parameter->setValue('%' . $parameter->getValue() . '%', $parameter->getType());
$this->parameters[] = $parameter;
return $this->expr->like($this->rootAlias . '.' . $comparison->getField(), $placeholder);
return $this->expr->like($field, $placeholder);
default:
$operator = self::convertComparisonOperator($comparison->getOperator());
if ($operator) {
$this->parameters[] = $parameter;
return new Expr\Comparison(
$this->rootAlias . '.' . $comparison->getField(),
$field,
$operator,
$placeholder
);

View File

@ -459,6 +459,24 @@ class QueryBuilder
return $aliases;
}
/**
* Gets all the aliases that have been used in the query.
* Including all select root aliases and join aliases
*
* <code>
* $qb = $em->createQueryBuilder()
* ->select('u')
* ->from('User', 'u')
* ->join('u.articles','a';
*
* $qb->getAllAliases(); // array('u','a')
* </code>
* @return array
*/
public function getAllAliases() {
return array_merge($this->getRootAliases(),array_keys($this->joinRootAliases));
}
/**
* Gets the root entities of the query. This is the entity aliases involved
* in the construction of the query.
@ -1221,8 +1239,12 @@ class QueryBuilder
*/
public function addCriteria(Criteria $criteria)
{
$rootAlias = $this->getRootAlias();
$visitor = new QueryExpressionVisitor($rootAlias);
$allAliases = $this->getAllAliases();
if ( ! isset($allAliases[0])) {
throw new \RuntimeException('No aliases are set before invoking addCriteria().');
}
$visitor = new QueryExpressionVisitor($this->getAllAliases());
if ($whereExpression = $criteria->getWhereExpression()) {
$this->andWhere($visitor->dispatch($whereExpression));
@ -1233,7 +1255,20 @@ class QueryBuilder
if ($criteria->getOrderings()) {
foreach ($criteria->getOrderings() as $sort => $order) {
$this->addOrderBy($rootAlias . '.' . $sort, $order);
$hasValidAlias = false;
foreach($allAliases as $alias) {
if(strpos($sort . '.', $alias . '.') === 0) {
$hasValidAlias = true;
break;
}
}
if(!$hasValidAlias) {
$sort = $allAliases[0] . '.' . $sort;
}
$this->addOrderBy($sort, $order);
}
}

View File

@ -47,7 +47,7 @@ class QueryExpressionVisitorTest extends \PHPUnit_Framework_TestCase
*/
protected function setUp()
{
$this->visitor = new QueryExpressionVisitor('o');
$this->visitor = new QueryExpressionVisitor(['o','p']);
}
/**
@ -89,6 +89,10 @@ class QueryExpressionVisitorTest extends \PHPUnit_Framework_TestCase
// Test parameter conversion
array($cb->eq('object.field', 'value'), $qb->eq('o.object.field', ':object_field'), new Parameter('object_field', 'value')),
// Test alternative rootAlias
array($cb->eq('p.field', 'value'), $qb->eq('p.field', ':p_field'), new Parameter('p_field', 'value')),
array($cb->eq('p.object.field', 'value'), $qb->eq('p.object.field', ':p_object_field'), new Parameter('p_object_field', 'value')),
);
}

View File

@ -522,6 +522,22 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('u.field DESC', (string) $orderBy[0]);
}
public function testAddCriteriaOrderOnJoinAlias()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->join('u.article','a');
$criteria = new Criteria();
$criteria->orderBy(array('a.field' => Criteria::DESC));
$qb->addCriteria($criteria);
$this->assertCount(1, $orderBy = $qb->getDQLPart('orderBy'));
$this->assertEquals('a.field DESC', (string) $orderBy[0]);
}
public function testAddCriteriaLimit()
{
$qb = $this->_em->createQueryBuilder();
@ -847,6 +863,69 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(2, $expr->count(), "Modifying the second query should affect the first one.");
}
/**
* @group DDC-3108
*/
public function testAddCriteriaWhereWithJoinAlias()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('alias1')->from('Doctrine\Tests\Models\CMS\CmsUser', 'alias1');
$qb->join('alias1.articles','alias2');
$criteria = new Criteria();
$criteria->where($criteria->expr()->eq('field', 'value1'));
$criteria->andWhere($criteria->expr()->gt('alias2.field', 'value2'));
$qb->addCriteria($criteria);
$this->assertEquals('alias1.field = :field AND alias2.field > :alias2_field', (string) $qb->getDQLPart('where'));
$this->assertSame('value1', $qb->getParameter('field')->getValue());
$this->assertSame('value2', $qb->getParameter('alias2_field')->getValue());
}
/**
* @group DDC-3108
*/
public function testAddCriteriaWhereWithDefaultAndJoinAlias()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('alias1')->from('Doctrine\Tests\Models\CMS\CmsUser', 'alias1');
$qb->join('alias1.articles','alias2');
$criteria = new Criteria();
$criteria->where($criteria->expr()->eq('alias1.field', 'value1'));
$criteria->andWhere($criteria->expr()->gt('alias2.field', 'value2'));
$qb->addCriteria($criteria);
$this->assertEquals('alias1.field = :alias1_field AND alias2.field > :alias2_field', (string) $qb->getDQLPart('where'));
$this->assertSame('value1', $qb->getParameter('alias1_field')->getValue());
$this->assertSame('value2', $qb->getParameter('alias2_field')->getValue());
}
/**
* @group DDC-3108
*/
public function testAddCriteriaWhereOnJoinAliasWithDuplicateFields()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('alias1')->from('Doctrine\Tests\Models\CMS\CmsUser', 'alias1');
$qb->join('alias1.articles','alias2');
$criteria = new Criteria();
$criteria->where($criteria->expr()->eq('alias1.field', 'value1'));
$criteria->andWhere($criteria->expr()->gt('alias2.field', 'value2'));
$criteria->andWhere($criteria->expr()->lt('alias2.field', 'value3'));
$qb->addCriteria($criteria);
$this->assertEquals('(alias1.field = :alias1_field AND alias2.field > :alias2_field) AND alias2.field < :alias2_field_2', (string) $qb->getDQLPart('where'));
$this->assertSame('value1', $qb->getParameter('alias1_field')->getValue());
$this->assertSame('value2', $qb->getParameter('alias2_field')->getValue());
$this->assertSame('value3', $qb->getParameter('alias2_field_2')->getValue());
}
/**
* @group DDC-1933
*/
@ -902,6 +981,17 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('u', $qb->getRootAlias());
}
public function testGetAliasesAddedWithJoins()
{
$qb = $this->_em->createQueryBuilder()
->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->join('u.articles','a');
$this->assertEquals(array('u', 'a'), $qb->getAllAliases());
$this->assertEquals('u', $qb->getRootAlias());
}
public function testBCAddJoinWithoutRootAlias()
{
$qb = $this->_em->createQueryBuilder()