Skip to content

Commit

Permalink
Refacto getFixedQueryBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet committed Feb 26, 2021
1 parent a78062e commit 21db1a4
Showing 1 changed file with 22 additions and 38 deletions.
60 changes: 22 additions & 38 deletions src/Datagrid/ProxyQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,37 +190,8 @@ public function execute(array $params = [], $hydrationMode = null)
}
}

/* By default, always add a sort on the identifier fields of the first
* used entity in the query, because RDBMS do not guarantee a
* particular order when no ORDER BY clause is specified, or when
* the field used for sorting is not unique.
*/

$identifierFields = $queryBuilder
->getEntityManager()
->getMetadataFactory()
->getMetadataFor(current($queryBuilder->getRootEntities()))
->getIdentifierFieldNames();

$existingOrders = [];
/** @var Query\Expr\OrderBy $order */
foreach ($queryBuilder->getDQLPart('orderBy') as $order) {
foreach ($order->getParts() as $part) {
$existingOrders[] = trim(str_replace([Criteria::DESC, Criteria::ASC], '', $part));
}
}

foreach ($identifierFields as $identifierField) {
$order = $rootAlias.'.'.$identifierField;
if (!\in_array($order, $existingOrders, true)) {
$queryBuilder->addOrderBy(
$order,
$this->getSortOrder() // reusing the sort order is the most natural way to go
);
}
}

$query = $this->getFixedQueryBuilder($queryBuilder)->getQuery();

foreach ($this->hints as $name => $value) {
$query->setHint($name, $value);
}
Expand Down Expand Up @@ -358,27 +329,40 @@ final public function setHint($name, $value)
}

/**
* This method alters the query to return a clean set of object with a working
* set of Object.
* This method alters the query in order to
* - add a sort on the identifier fields of the first used entity in the query,
* because RDBMS do not guarantee a particular order when no ORDER BY clause
* is specified, or when the field used for sorting is not unique.
* - add a group by on the identifier fields in order to not display the same
* entity twice if entityJoin was used with a one to many relation.
*
* @return QueryBuilder
*/
protected function getFixedQueryBuilder(QueryBuilder $queryBuilder)
{
$rootAlias = current($queryBuilder->getRootAliases());

// step 1 : retrieve the identifier columns
$identifierFields = $queryBuilder
->getEntityManager()
->getMetadataFactory()
->getMetadataFor(current($queryBuilder->getRootEntities()))
->getIdentifierFieldNames();

// step 2 : group by identifier columns
if ($this->isDistinct()) {
$queryBuilder->resetDQLPart('groupBy');
foreach ($identifierFields as $identifierField) {
$queryBuilder->addGroupBy(sprintf('%s.%s', $rootAlias, $identifierField));
$existingOrders = [];
foreach ($queryBuilder->getDQLPart('orderBy') as $order) {
foreach ($order->getParts() as $part) {
$existingOrders[] = trim(str_replace([Criteria::DESC, Criteria::ASC], '', $part));
}
}

$queryBuilder->resetDQLPart('groupBy');

foreach ($identifierFields as $identifierField) {
$field = $rootAlias.'.'.$identifierField;

$queryBuilder->addGroupBy($field);
if (!\in_array($field, $existingOrders, true)) {
$queryBuilder->addOrderBy($field, $this->getSortOrder());
}
}

Expand Down

0 comments on commit 21db1a4

Please sign in to comment.