Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/dev/1.10' into 1.10
Browse files Browse the repository at this point in the history
  • Loading branch information
rgrebenchuk committed Feb 7, 2017
2 parents ad30034 + 958c548 commit 776b604
Show file tree
Hide file tree
Showing 20 changed files with 419 additions and 829 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
<?php

namespace Oro\Bundle\DataGridBundle\Extension\Sorter;

use Doctrine\ORM\Query\Expr\From;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\Expr\Select;

use Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration;
use Oro\Bundle\DataGridBundle\Datasource\DatasourceInterface;
use Oro\Bundle\DataGridBundle\Extension\AbstractExtension;
use Oro\Bundle\DataGridBundle\Datasource\Orm\OrmDatasource;
use Oro\Bundle\EntityBundle\ORM\DatabaseDriverInterface;
use Oro\Bundle\EntityBundle\ORM\EntityClassResolver;

class PostgresqlGridModifier extends AbstractExtension
{
const PRIORITY = -261;

/** @var string */
protected $databaseDriver;

/** @var EntityClassResolver */
protected $entityClassResolver;

/**
* @param string $databaseDriver
* @param EntityClassResolver $entityClassResolver
*/
public function __construct($databaseDriver, EntityClassResolver $entityClassResolver)
{
$this->databaseDriver = $databaseDriver;
$this->entityClassResolver = $entityClassResolver;
}

/**
* {@inheritdoc}
*/
public function isApplicable(DatagridConfiguration $config)
{
return $this->databaseDriver === DatabaseDriverInterface::DRIVER_POSTGRESQL;
}

/**
* {@inheritDoc}
*/
public function getPriority()
{
return self::PRIORITY;
}

/**
* Add sorting by identifier because postgresql return rows in different order on two the same sql, but
* different LIMIT number
*
* @param DatagridConfiguration $config
* @param DatasourceInterface $datasource
* @return mixed|void
*/
public function visitDatasource(DatagridConfiguration $config, DatasourceInterface $datasource)
{
//getQueryBuilder exists only in datagrid orm datasource
if (!$datasource instanceof OrmDatasource) {
return;
}

$entityClassName = $this->getEntityClassName($config);
/** @var QueryBuilder $queryBuilder */
$queryBuilder = $datasource->getQueryBuilder();

if (!$entityClassName) {
return;
}

$fromParts = $queryBuilder->getDQLPart('from');
$alias = false;

$metadata = $queryBuilder->getEntityManager()->getClassMetadata($entityClassName);
$identifier = $metadata->getSingleIdentifierFieldName();

/** @var From $fromPart */
foreach ($fromParts as $fromPart) {
if ($this->entityClassResolver->getEntityClass($fromPart->getFrom()) == $entityClassName) {
$alias = $fromPart->getAlias();
break;
}
}

if ($alias && $this->isAllowedAddingSorting($alias, $identifier, $queryBuilder)) {
$field = $alias . '.' . $identifier;
$orderBy = $queryBuilder->getDQLPart('orderBy');
if (!isset($orderBy[$field])) {
if ($this->isDistinct($queryBuilder)) {
$this->ensureIdentifierSelected($queryBuilder, $field);
}
$queryBuilder->addOrderBy($field, 'ASC');
}
}
}

/**
* @param DatagridConfiguration $config
*
* @return null|string
*/
protected function getEntityClassName(DatagridConfiguration $config)
{
$entityClassName = $config->offsetGetByPath('[extended_entity_name]');
if ($entityClassName) {
return $entityClassName;
}

$from = $config->offsetGetByPath('[source][query][from]');
if (count($from) !== 0) {
return $this->entityClassResolver->getEntityClass($from[0]['table']);
}

return null;
}

/**
* @param string $alias
* @param string $identifier
* @param QueryBuilder $queryBuilder
* @return bool
*/
protected function isAllowedAddingSorting($alias, $identifier, QueryBuilder $queryBuilder)
{
$groupByParts = $queryBuilder->getDQLPart('groupBy');

if (!count($groupByParts)) {
return true;
}

foreach ($groupByParts as $groupBy) {
if (in_array($alias.'.'.$identifier, $groupBy->getParts(), true) !== false) {
return true;
}
}

return false;
}

/**
* @param QueryBuilder $queryBuilder
* @return bool
*/
protected function isDistinct(QueryBuilder $queryBuilder)
{
if ($queryBuilder->getDQLPart('distinct')) {
return true;
}

foreach ($queryBuilder->getDQLPart('select') as $select) {
$selectString = ltrim(strtolower((string)$select));
if (strpos($selectString, 'distinct ') === 0) {
return true;
}
}

return false;
}

/**
* @param QueryBuilder $queryBuilder
* @param string $field
*/
protected function ensureIdentifierSelected(QueryBuilder $queryBuilder, $field)
{
$isSelected = false;
/** @var Select $select */
foreach ($queryBuilder->getDQLPart('select') as $select) {
$selectString = ltrim(strtolower((string)$select));
if (strpos($selectString, 'distinct ') === 0) {
$selectString = substr($selectString, 9);
}
// if field itself or field with alias
if ($selectString === $field ||
(
strpos($selectString, $field) === 0 &&
strpos(strtolower(ltrim(substr($selectString, strlen($field)))), 'as ') === 0
)
) {
$isSelected = true;
break;
}
}

if (!$isSelected) {
$queryBuilder->addSelect($field);
}
}
}

This file was deleted.

8 changes: 5 additions & 3 deletions src/Oro/Bundle/DataGridBundle/Resources/config/extensions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ parameters:
oro_datagrid.extension.totals.class: Oro\Bundle\DataGridBundle\Extension\Totals\OrmTotalsExtension
oro_datagrid.extension.columns.class: Oro\Bundle\DataGridBundle\Extension\Columns\ColumnsExtension
oro_datagrid.extension.mode.class: Oro\Bundle\DataGridBundle\Extension\Mode\ModeExtension
oro_datagrid.extension.postgresql_grid_modifier.class: Oro\Bundle\DataGridBundle\Extension\Sorter\PostgresqlGridModifier
oro_datagrid.extension.board.class: Oro\Bundle\DataGridBundle\Extension\Board\BoardExtension
oro_datagrid.extension.appearance.class: Oro\Bundle\DataGridBundle\Extension\Appearance\AppearanceExtension

Expand Down Expand Up @@ -135,10 +136,11 @@ services:
tags:
- { name: oro_datagrid.extension }

oro_datagrid.extension.precise_order_by:
class: Oro\Bundle\DataGridBundle\Extension\Sorter\PreciseOrderByExtension
oro_datagrid.extension.postgresql_grid_modifier:
class: %oro_datagrid.extension.postgresql_grid_modifier.class%
arguments:
- '@oro_entity.query_hint_resolver'
- %database_driver%
- '@oro_entity.orm.entity_class_resolver'
tags:
- { name: oro_datagrid.extension }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,6 @@ datagrid:
from:
- { table: OroCRMContactBundle:Group, alias: g }
```
Important notes
---------------
By default all datagrids that use ORM datasource is marked by [HINT_PRECISE_ORDER_BY](../../../../../../Component/DoctrineUtils/README.md#preciseorderbywalker-class) query hint. This guarantee that rows are sorted in the same way independent from a state of SQL server and from values of OFFSET and LIMIT clauses. More details you can find in [PostgreSQL documentation](https://www.postgresql.org/docs/8.1/static/queries-limit.html).
If you need to disable this behaviour for your datagrid the following configuration can be used:
```yaml

datagrids:
DATAGRID_NAME_HERE:
source:
type: orm
query:
...
hints:
- { name: HINT_PRECISE_ORDER_BY, value: false }
```
Query hints
-----------
Expand Down
Loading

0 comments on commit 776b604

Please sign in to comment.