Skip to content

Commit

Permalink
BAP-14290: PostgresqlGridModifier add duplicate Order by identifier t…
Browse files Browse the repository at this point in the history
…o final query (#9530)

- Added fixes to prevent fields duplication in OrderBy query part
  • Loading branch information
ikrynychanskyi authored and yurio committed Apr 13, 2017
1 parent 8784f61 commit 9a23f73
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public function visitDatasource(DatagridConfiguration $config, DatasourceInterfa
if ($alias && $this->isAllowedAddingSorting($alias, $identifier, $queryBuilder)) {
$field = $alias . '.' . $identifier;
$orderBy = $queryBuilder->getDQLPart('orderBy');
if (!isset($orderBy[$field])) {
if (!$this->hasOrderByField($orderBy, $field)) {
if ($this->isDistinct($queryBuilder)) {
$this->ensureIdentifierSelected($queryBuilder, $field);
}
Expand All @@ -98,6 +98,23 @@ public function visitDatasource(DatagridConfiguration $config, DatasourceInterfa
}
}

/**
* Check field already exists in orders part
*
* @param array $orderBy
* @param string $field
* @return bool
*/
protected function hasOrderByField($orderBy, $field)
{
foreach ($orderBy as $order) {
if (preg_match(sprintf('/(^|\s)%s\s/i', $field), $order)) {
return true;
}
}
return false;
}

/**
* @param DatagridConfiguration $config
*
Expand Down Expand Up @@ -127,7 +144,7 @@ protected function isAllowedAddingSorting($alias, $identifier, QueryBuilder $que

$selectPartsWithAggregation = array_filter($selectParts, function ($selectPart) use ($forbiddenFunctions) {
foreach ($forbiddenFunctions as $functionName) {
if (false !== stripos($selectPart, $functionName)) {
if (false !== stripos($selectPart, $functionName . '(')) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

namespace Oro\Bundle\DataGridBundle\Tests\Unit\Extension\Sorter;

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\Expr\OrderBy;

use Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration;
use Oro\Bundle\DataGridBundle\Datasource\Orm\OrmDatasource;
use Oro\Bundle\DataGridBundle\Extension\Sorter\PostgresqlGridModifier;
use Oro\Bundle\EntityBundle\ORM\EntityClassResolver;

class PostgresqlGridModifierTest extends \PHPUnit_Framework_TestCase
{
/**
* @var PostgresqlGridModifier
*/
protected $extension;

protected $entityClassResolver;

public function setUp()
{
$this->entityClassResolver = $this->getMockBuilder(EntityClassResolver::class)
->disableOriginalConstructor()
->getMock();
$this->extension = new PostgresqlGridModifier('pdo_pgsql', $this->entityClassResolver);
}

/**
* @dataProvider visitDatasourceDataProvider
*/
public function testVisitDatasource($orderBy, $expected)
{
$em = $this->getMockBuilder(EntityManager::class)
->disableOriginalConstructor()
->getMock();

$metadata = $this->getMockBuilder(ClassMetadata::class)
->disableOriginalConstructor()
->getMock();

$em->expects(self::once())
->method('getClassMetadata')
->with('Test\Entity')
->willReturn($metadata);

$metadata->expects(self::once())
->method('getSingleIdentifierFieldName')
->willReturn('id');

$qb = new QueryBuilder($em);
$qb->select('e.id')->from('Test\Entity', 'e');

if (!empty($orderBy)) {
$orderByExpr = new OrderBy();
foreach ($orderBy as $field => $des) {
$orderByExpr->add($field, $des);
}
$qb->addOrderBy($orderByExpr);
}

$datasource = $this->getMockBuilder(OrmDatasource::class)
->disableOriginalConstructor()
->getMock();

$datasource->expects(self::once())
->method('getQueryBuilder')
->willReturn($qb);

$this->entityClassResolver->expects($this->any())
->method('getEntityClass')
->willReturn('Test\Entity');

$dataGridConfig = DatagridConfiguration::create([
'sorters' => [
'columns' => []
],
'source' => [
'type' => 'orm',
'query' => [
'from' => [
[
'table' => 'Test\Entity',
'alias' => 'e'
]
]
]
]
]);

$this->extension->visitDatasource(
$dataGridConfig,
$datasource
);

self::assertEquals(
$expected,
$qb->getDQL()
);
}

/**
* @return array
*/
public function visitDatasourceDataProvider()
{
return [
'OrderBy has only primary key field' => [
['e.id' => 'ASC'],
'SELECT e.id FROM Test\Entity e ORDER BY e.id ASC'
],
'OrderBy has no primary key field' => [
['e.name' => 'ASC'],
'SELECT e.id FROM Test\Entity e ORDER BY e.name ASC, e.id ASC'
],
'OrderBy has no fields' => [
[],
'SELECT e.id FROM Test\Entity e ORDER BY e.id ASC'
],
'OrderBy has primary key field' => [
['e.name' => 'DESC', 'e.id' => 'DESC'],
'SELECT e.id FROM Test\Entity e ORDER BY e.name DESC, e.id DESC'
],
'OrderBy has primary key field as first' => [
['e.id' => 'DESC', 'e.name' => 'ASC'],
'SELECT e.id FROM Test\Entity e ORDER BY e.id DESC, e.name ASC'
],
];
}
}

0 comments on commit 9a23f73

Please sign in to comment.