Fixed filter logic for exclusion of entities. Before parts with null values as property value were wrongly not shown

This fixes  issue #658
This commit is contained in:
Jan Böhmer 2024-08-23 22:58:04 +02:00
parent 5231dbd6e7
commit 7fc3153dde
2 changed files with 17 additions and 5 deletions

View file

@ -137,7 +137,7 @@ class EntityConstraint extends AbstractConstraint
} }
//We need to handle null values differently, as they can not be compared with == or != //We need to handle null values differently, as they can not be compared with == or !=
if (!$this->value instanceof AbstractDBElement) { if ($this->value === null) {
if($this->operator === '=' || $this->operator === 'INCLUDING_CHILDREN') { if($this->operator === '=' || $this->operator === 'INCLUDING_CHILDREN') {
$queryBuilder->andWhere(sprintf("%s IS NULL", $this->property)); $queryBuilder->andWhere(sprintf("%s IS NULL", $this->property));
return; return;
@ -152,8 +152,9 @@ class EntityConstraint extends AbstractConstraint
} }
if($this->operator === '=' || $this->operator === '!=') { if($this->operator === '=' || $this->operator === '!=') {
$this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, $this->operator, $this->value); //Include null values on != operator, so that really all values are returned that are not equal to the given value
return; $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, $this->operator, $this->value, $this->operator === '!=');
return;
} }
//Otherwise retrieve the children list and apply the operator to it //Otherwise retrieve the children list and apply the operator to it
@ -168,7 +169,8 @@ class EntityConstraint extends AbstractConstraint
} }
if ($this->operator === 'EXCLUDING_CHILDREN') { if ($this->operator === 'EXCLUDING_CHILDREN') {
$this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, 'NOT IN', $list); //Include null values in the result, so that all elements that are not in the list are returned
$this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, 'NOT IN', $list, true);
return; return;
} }
} else { } else {

View file

@ -56,8 +56,14 @@ trait FilterTrait
/** /**
* Adds a simple constraint in the form of (property OPERATOR value) (e.g. "part.name = :name") to the given query builder. * Adds a simple constraint in the form of (property OPERATOR value) (e.g. "part.name = :name") to the given query builder.
* @param QueryBuilder $queryBuilder The query builder to add the constraint to
* @param string $property The property to compare
* @param string $parameterIdentifier The identifier for the parameter
* @param string $comparison_operator The comparison operator to use
* @param mixed $value The value to compare to
* @param bool $include_null If true, the result of this constraint will also include null values of this property (useful for exclusion filters)
*/ */
protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, mixed $value): void protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, mixed $value, bool $include_null = false): void
{ {
if ($comparison_operator === 'IN' || $comparison_operator === 'NOT IN') { if ($comparison_operator === 'IN' || $comparison_operator === 'NOT IN') {
$expression = sprintf("%s %s (:%s)", $property, $comparison_operator, $parameterIdentifier); $expression = sprintf("%s %s (:%s)", $property, $comparison_operator, $parameterIdentifier);
@ -65,6 +71,10 @@ trait FilterTrait
$expression = sprintf("%s %s :%s", $property, $comparison_operator, $parameterIdentifier); $expression = sprintf("%s %s :%s", $property, $comparison_operator, $parameterIdentifier);
} }
if ($include_null) {
$expression = sprintf("(%s OR %s IS NULL)", $expression, $property);
}
if($this->useHaving || $this->isAggregateFunctionString($property)) { //If the property is an aggregate function, we have to use the "having" instead of the "where" if($this->useHaving || $this->isAggregateFunctionString($property)) { //If the property is an aggregate function, we have to use the "having" instead of the "where"
$queryBuilder->andHaving($expression); $queryBuilder->andHaving($expression);
} else { } else {