Merge branch 'hotfix/#1212-fix-regression-that-hid-join-aliases-in-criteria-expressions'
Close #1212
This commit is contained in:
commit
fe4d46014d
@ -45,9 +45,9 @@ class QueryExpressionVisitor extends ExpressionVisitor
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $rootAlias;
|
private $queryAliases;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Expr
|
* @var Expr
|
||||||
@ -62,11 +62,11 @@ class QueryExpressionVisitor extends ExpressionVisitor
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param string $rootAlias
|
* @param array $queryAliases
|
||||||
*/
|
*/
|
||||||
public function __construct($rootAlias)
|
public function __construct($queryAliases)
|
||||||
{
|
{
|
||||||
$this->rootAlias = $rootAlias;
|
$this->queryAliases = $queryAliases;
|
||||||
$this->expr = new Expr();
|
$this->expr = new Expr();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +131,20 @@ class QueryExpressionVisitor extends ExpressionVisitor
|
|||||||
*/
|
*/
|
||||||
public function walkComparison(Comparison $comparison)
|
public function walkComparison(Comparison $comparison)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if ( ! isset($this->queryAliases[0])) {
|
||||||
|
throw new QueryException('No aliases are set before invoking walkComparison().');
|
||||||
|
}
|
||||||
|
|
||||||
|
$field = $this->queryAliases[0] . '.' . $comparison->getField();
|
||||||
|
|
||||||
|
foreach($this->queryAliases as $alias) {
|
||||||
|
if(strpos($comparison->getField() . '.', $alias . '.') === 0) {
|
||||||
|
$field = $comparison->getField();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$parameterName = str_replace('.', '_', $comparison->getField());
|
$parameterName = str_replace('.', '_', $comparison->getField());
|
||||||
|
|
||||||
foreach($this->parameters as $parameter) {
|
foreach($this->parameters as $parameter) {
|
||||||
@ -146,38 +160,38 @@ class QueryExpressionVisitor extends ExpressionVisitor
|
|||||||
switch ($comparison->getOperator()) {
|
switch ($comparison->getOperator()) {
|
||||||
case Comparison::IN:
|
case Comparison::IN:
|
||||||
$this->parameters[] = $parameter;
|
$this->parameters[] = $parameter;
|
||||||
return $this->expr->in($this->rootAlias . '.' . $comparison->getField(), $placeholder);
|
return $this->expr->in($field, $placeholder);
|
||||||
|
|
||||||
case Comparison::NIN:
|
case Comparison::NIN:
|
||||||
$this->parameters[] = $parameter;
|
$this->parameters[] = $parameter;
|
||||||
return $this->expr->notIn($this->rootAlias . '.' . $comparison->getField(), $placeholder);
|
return $this->expr->notIn($field, $placeholder);
|
||||||
|
|
||||||
case Comparison::EQ:
|
case Comparison::EQ:
|
||||||
case Comparison::IS:
|
case Comparison::IS:
|
||||||
if ($this->walkValue($comparison->getValue()) === null) {
|
if ($this->walkValue($comparison->getValue()) === null) {
|
||||||
return $this->expr->isNull($this->rootAlias . '.' . $comparison->getField());
|
return $this->expr->isNull($field);
|
||||||
}
|
}
|
||||||
$this->parameters[] = $parameter;
|
$this->parameters[] = $parameter;
|
||||||
return $this->expr->eq($this->rootAlias . '.' . $comparison->getField(), $placeholder);
|
return $this->expr->eq($field, $placeholder);
|
||||||
|
|
||||||
case Comparison::NEQ:
|
case Comparison::NEQ:
|
||||||
if ($this->walkValue($comparison->getValue()) === null) {
|
if ($this->walkValue($comparison->getValue()) === null) {
|
||||||
return $this->expr->isNotNull($this->rootAlias . '.' . $comparison->getField());
|
return $this->expr->isNotNull($field);
|
||||||
}
|
}
|
||||||
$this->parameters[] = $parameter;
|
$this->parameters[] = $parameter;
|
||||||
return $this->expr->neq($this->rootAlias . '.' . $comparison->getField(), $placeholder);
|
return $this->expr->neq($field, $placeholder);
|
||||||
|
|
||||||
case Comparison::CONTAINS:
|
case Comparison::CONTAINS:
|
||||||
$parameter->setValue('%' . $parameter->getValue() . '%', $parameter->getType());
|
$parameter->setValue('%' . $parameter->getValue() . '%', $parameter->getType());
|
||||||
$this->parameters[] = $parameter;
|
$this->parameters[] = $parameter;
|
||||||
return $this->expr->like($this->rootAlias . '.' . $comparison->getField(), $placeholder);
|
return $this->expr->like($field, $placeholder);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$operator = self::convertComparisonOperator($comparison->getOperator());
|
$operator = self::convertComparisonOperator($comparison->getOperator());
|
||||||
if ($operator) {
|
if ($operator) {
|
||||||
$this->parameters[] = $parameter;
|
$this->parameters[] = $parameter;
|
||||||
return new Expr\Comparison(
|
return new Expr\Comparison(
|
||||||
$this->rootAlias . '.' . $comparison->getField(),
|
$field,
|
||||||
$operator,
|
$operator,
|
||||||
$placeholder
|
$placeholder
|
||||||
);
|
);
|
||||||
|
@ -459,6 +459,24 @@ class QueryBuilder
|
|||||||
return $aliases;
|
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
|
||||||
|
*/
|
||||||
|
private function getAllAliases() {
|
||||||
|
return array_merge($this->getRootAliases(),array_keys($this->joinRootAliases));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the root entities of the query. This is the entity aliases involved
|
* Gets the root entities of the query. This is the entity aliases involved
|
||||||
* in the construction of the query.
|
* in the construction of the query.
|
||||||
@ -1216,13 +1234,17 @@ class QueryBuilder
|
|||||||
* Overrides firstResult and maxResults if they're set.
|
* Overrides firstResult and maxResults if they're set.
|
||||||
*
|
*
|
||||||
* @param Criteria $criteria
|
* @param Criteria $criteria
|
||||||
*
|
|
||||||
* @return QueryBuilder
|
* @return QueryBuilder
|
||||||
|
* @throws Query\QueryException
|
||||||
*/
|
*/
|
||||||
public function addCriteria(Criteria $criteria)
|
public function addCriteria(Criteria $criteria)
|
||||||
{
|
{
|
||||||
$rootAlias = $this->getRootAlias();
|
$allAliases = $this->getAllAliases();
|
||||||
$visitor = new QueryExpressionVisitor($rootAlias);
|
if ( ! isset($allAliases[0])) {
|
||||||
|
throw new Query\QueryException('No aliases are set before invoking addCriteria().');
|
||||||
|
}
|
||||||
|
|
||||||
|
$visitor = new QueryExpressionVisitor($this->getAllAliases());
|
||||||
|
|
||||||
if ($whereExpression = $criteria->getWhereExpression()) {
|
if ($whereExpression = $criteria->getWhereExpression()) {
|
||||||
$this->andWhere($visitor->dispatch($whereExpression));
|
$this->andWhere($visitor->dispatch($whereExpression));
|
||||||
@ -1233,7 +1255,20 @@ class QueryBuilder
|
|||||||
|
|
||||||
if ($criteria->getOrderings()) {
|
if ($criteria->getOrderings()) {
|
||||||
foreach ($criteria->getOrderings() as $sort => $order) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class QueryExpressionVisitorTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
$this->visitor = new QueryExpressionVisitor('o');
|
$this->visitor = new QueryExpressionVisitor(array('o','p'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,6 +89,10 @@ class QueryExpressionVisitorTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
// Test parameter conversion
|
// Test parameter conversion
|
||||||
array($cb->eq('object.field', 'value'), $qb->eq('o.object.field', ':object_field'), new Parameter('object_field', 'value')),
|
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')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +522,25 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
$this->assertEquals('u.field DESC', (string) $orderBy[0]);
|
$this->assertEquals('u.field DESC', (string) $orderBy[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-3108
|
||||||
|
*/
|
||||||
|
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()
|
public function testAddCriteriaLimit()
|
||||||
{
|
{
|
||||||
$qb = $this->_em->createQueryBuilder();
|
$qb = $this->_em->createQueryBuilder();
|
||||||
@ -847,6 +866,69 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
$this->assertEquals(2, $expr->count(), "Modifying the second query should affect the first one.");
|
$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
|
* @group DDC-1933
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user