Skip to content

Commit

Permalink
Use RegEx to match if queryPart contains OR/AND (#8453)
Browse files Browse the repository at this point in the history
This allows fixes cases of queries that contain line feeds or tabs but
do not benefit from automatic wrapping of parenthesis.
  • Loading branch information
Warxcell committed Feb 22, 2021
1 parent 074346b commit a70c73a
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 2 deletions.
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/Query/Expr/Composite.php
Expand Up @@ -22,7 +22,7 @@

use function implode;
use function is_object;
use function stripos;
use function preg_match;

/**
* Expression class for building DQL and parts.
Expand Down Expand Up @@ -63,7 +63,7 @@ private function processQueryPart($part)
}

// Fixes DDC-1237: User may have added a where item containing nested expression (with "OR" or "AND")
if (stripos($queryPart, ' OR ') !== false || stripos($queryPart, ' AND ') !== false) {
if (preg_match('/\s(OR|AND)\s/', $queryPart)) {
return $this->preSeparator . $queryPart . $this->postSeparator;
}

Expand Down
112 changes: 112 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/QueryBuilderParenthesis.php
@@ -0,0 +1,112 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional;

use Doctrine\Tests\OrmFunctionalTestCase;

class QueryBuilderParenthesis extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$this->_schemaTool->createSchema(
[
$this->_em->getClassMetadata(QueryBuilderParenthesisEntity::class),
]
);
}

protected function tearDown(): void
{
parent::tearDown();

$this->_schemaTool->dropSchema(
[
$this->_em->getClassMetadata(QueryBuilderParenthesisEntity::class),
]
);
}

public function testParenthesisOnSingleLine(): void
{
$queryBuilder = $this->_em->createQueryBuilder();
$queryBuilder->select('o')->from(QueryBuilderParenthesisEntity::class, 'o');
$queryBuilder->andWhere('o.property3 = :value3')->setParameter('value3', 'x');
$queryBuilder->andWhere('o.property1 = :value1 OR o.property2 = :value2');
$queryBuilder->setParameter('value1', 'x');
$queryBuilder->setParameter('value2', 'x');

$query = $queryBuilder->getQuery();
$results = $query->getResult();
$this->assertCount(0, $results);

$dql = $query->getDQL();

$this->assertSame(
'SELECT o FROM ' . QueryBuilderParenthesisEntity::class . ' o WHERE o.property3 = :value3 AND (o.property1 = :value1 OR o.property2 = :value2)',
$dql
);
}

public function testParenthesisOnMultiLine(): void
{
$queryBuilder = $this->_em->createQueryBuilder();
$queryBuilder->select('o')->from(QueryBuilderParenthesisEntity::class, 'o');
$queryBuilder->andWhere('o.property3 = :value3')->setParameter('value3', 'x');

$queryBuilder->andWhere(
'o.property1 = :value1
OR o.property2 = :value2'
);
$queryBuilder->setParameter('value1', 'x');
$queryBuilder->setParameter('value2', 'x');

$query = $queryBuilder->getQuery();
$results = $query->getResult();
$this->assertCount(0, $results);

$dql = $query->getDQL();

$this->assertSame(
'SELECT o FROM ' . QueryBuilderParenthesisEntity::class . ' o WHERE o.property3 = :value3 AND (o.property1 = :value1
OR o.property2 = :value2)',
$dql
);
}
}


/**
* @Entity
*/
class QueryBuilderParenthesisEntity
{
/**
* @var int|null
* @Column(type="integer")
* @Id
* @GeneratedValue
*/
public $id;

/**
* @var string|null
* @Column()
*/
public $property1;

/**
* @var string|null
* @Column()
*/
public $property2;

/**
* @var string|null
* @Column()
*/
public $property3;
}

0 comments on commit a70c73a

Please sign in to comment.