Skip to content

Commit

Permalink
Use a static array to store the conditions required by each admin
Browse files Browse the repository at this point in the history
  • Loading branch information
phansys committed Mar 23, 2021
1 parent 9907175 commit cc1df5c
Showing 1 changed file with 41 additions and 21 deletions.
62 changes: 41 additions & 21 deletions src/Filter/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ abstract class Filter extends BaseFilter
protected $active = false;

/**
* @var Orx
* Holds an array of `orX` expressions used by each admin when the condition
* equals the value on `FilterInterface::CONDITION_OR`, using the admin code
* as index.
*
* @var array<string, Orx>
*/
private $orExpression;
private static $orExpressionsByAdmin = [];

/**
* NEXT_MAJOR change $query type for Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQueryInterface.
Expand Down Expand Up @@ -107,8 +111,7 @@ protected function applyWhere(BaseProxyQueryInterface $query, $parameter)
}

if (self::CONDITION_OR === $this->getCondition()) {
$condition = $this->getOrExpression($query);
$condition->add($parameter);
$this->addOrParameter($query, $parameter);
} else {
$query->getQueryBuilder()->andWhere($parameter);
}
Expand Down Expand Up @@ -155,52 +158,69 @@ protected function getNewParameterName(BaseProxyQueryInterface $query)
}

/**
* Returns the reference to the `Orx` expression used in the `where` clause.
* Adds the parameter to the corresponding `Orx` expression used in the `where` clause.
* If it doesn't exist, a new one is created.
* This method uses a marker (":sonata_admin_datagrid_filter_query_marker") in
* This method groups the filter "OR" conditions based on the "admin_code" option. It this
* option is not set, it uses a marker (":sonata_admin_datagrid_filter_query_marker") in
* the resulting DQL in order to identify the corresponding "WHERE (...)" condition
* group each time it is required.
* It allows to get queries like "WHERE previous_condition = previous_value AND (filter_1 = value OR filter_2 = value OR ...)",
* where the logical "OR" operators added by the filters are grouped inside a condition,
* instead of having unfolded "WHERE ..." clauses like "WHERE previous_condition = previous_value OR filter_1 = value OR filter_2 = value OR ...",
* which will produce undesired results.
*
* TODO: Remove the logic related to the ":sonata_admin_datagrid_filter_query_marker" marker when
* the constraint for "sonata-project/admin-bundle" guarantees that the "admin_code" option is set.
*
* @param mixed $parameter
*/
private function getOrExpression(BaseProxyQueryInterface $query): Orx
private function addOrParameter(BaseProxyQueryInterface $query, $parameter): void
{
if (null !== $this->orExpression) {
return $this->orExpression;
$adminCode = $this->getOption('admin_code');
$orExpression = self::$orExpressionsByAdmin[$adminCode] ?? null;
if ($orExpression instanceof Orx) {
$orExpression->add($parameter);

return;
}

$qb = $query->getQueryBuilder();
$where = $qb->getDQLPart('where');

if ($where) {
// Search for the ":sonata_admin_datagrid_filter_query_marker" marker in order to
// get the `Orx` expression.
if (null === $adminCode && null !== $where) {
foreach ($where->getParts() as $expression) {
if (!$expression instanceof Orx) {
continue;
}

$expressionParts = $expression->getParts();

// Search for the ":sonata_admin_datagrid_filter_query_marker" marker in order to
// get the `Orx` expression.
if (isset($expressionParts[0]) && \is_string($expressionParts[0]) &&
0 === strpos($expressionParts[0], ':sonata_admin_datagrid_filter_query_marker')
) {
$this->orExpression = $expression;
$expression->add($parameter);

return $this->orExpression;
return;
}
}
}

// Create a new `Orx` expression, adding it to the `where` clause.
$this->orExpression = $qb->expr()->orX();
// Place ":sonata_admin_datagrid_filter_query_marker" parameter as marker for the `Orx` expression.
$this->orExpression->add($qb->expr()->isNull(':sonata_admin_datagrid_filter_query_marker'));
$qb->setParameter('sonata_admin_datagrid_filter_query_marker', 'sonata_admin.datagrid.filter_query.marker');
$qb->andWhere($this->orExpression);
// Create a new `Orx` expression.
$orExpression = $qb->expr()->orX();

if (null === $adminCode) {
// Add the ":sonata_admin_datagrid_filter_query_marker" parameter as marker for the `Orx` expression.
$orExpression->add($qb->expr()->isNull(':sonata_admin_datagrid_filter_query_marker'));
$qb->setParameter('sonata_admin_datagrid_filter_query_marker', 'sonata_admin.datagrid.filter_query.marker');
} else {
self::$orExpressionsByAdmin[$adminCode] = $orExpression;
}

$orExpression->add($parameter);

return $this->orExpression;
// Add the `Orx` expression to the `where` clause.
$qb->andWhere($orExpression);
}
}

0 comments on commit cc1df5c

Please sign in to comment.