From 2c514b309f6c19eeabde6afd00f801adc23239be Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Mon, 7 Sep 2026 14:52:19 +0200 Subject: [PATCH 1/5] Handle null data source in FilterException to prevent errors --- src/Query/Executor/FilterExecutor.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Query/Executor/FilterExecutor.php b/src/Query/Executor/FilterExecutor.php index d3eaa197..daa33f64 100644 --- a/src/Query/Executor/FilterExecutor.php +++ b/src/Query/Executor/FilterExecutor.php @@ -177,7 +177,9 @@ private function createCallbackException( return new FilterException( \sprintf('[FLARE] Query denied: %s / Callback: %s', $e->getMessage(), $errorMethod), code: $e->getCode(), previous: $e, method: $errorMethod, - source: \sprintf('tl_flare_filter.id=%s', $filter->getDataSource()->getFilterIdentifier() ?: '0'), + source: $filter->getDataSource() + ? \sprintf('tl_flare_filter.id=%s', $filter->getDataSource()->getFilterIdentifier() ?: '0') + : null, ); } -} \ No newline at end of file +} From 3905e8aacee41747e85eff39acaf886a629350c2 Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Mon, 7 Sep 2026 15:06:26 +0200 Subject: [PATCH 2/5] Add IN and NOT_IN operators to SimpleEquationElement; validate operator in SimpleEquationMod --- src/Engine/Mod/SimpleEquationMod.php | 7 +++++-- src/FilterElement/SimpleEquationElement.php | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Engine/Mod/SimpleEquationMod.php b/src/Engine/Mod/SimpleEquationMod.php index 176186f2..fefb9892 100644 --- a/src/Engine/Mod/SimpleEquationMod.php +++ b/src/Engine/Mod/SimpleEquationMod.php @@ -18,9 +18,12 @@ public static function getType(): string public function __invoke(Engine $engine, array $options): void { + $operator = SqlEquationOperator::match($options['operator'] + ?? throw new \InvalidArgumentException('Invalid equation operator provided')); + $filter = SimpleEquationElement::define( equationLeft: $options['operand1'], - equationOperator: $options['operator'], + equationOperator: $operator, equationRight: $options['operand2'], ); @@ -56,4 +59,4 @@ public function configureOptions(OptionsResolver $resolver): void ?? throw new \InvalidArgumentException('Invalid equation operator provided') ); } -} \ No newline at end of file +} diff --git a/src/FilterElement/SimpleEquationElement.php b/src/FilterElement/SimpleEquationElement.php index 2dd16704..a6091dba 100644 --- a/src/FilterElement/SimpleEquationElement.php +++ b/src/FilterElement/SimpleEquationElement.php @@ -44,9 +44,11 @@ public function __invoke(FilterInvocation $inv, FilterQueryBuilder $qb): void SqlEquationOperator::LESS_THAN_EQUALS => $qb->expr()->lte($operand, ':eq_right'), SqlEquationOperator::LIKE => $qb->expr()->like($operand, ':eq_right'), SqlEquationOperator::NOT_LIKE => $qb->expr()->notLike($operand, ':eq_right'), + SqlEquationOperator::IN => $qb->expr()->in($operand, ':eq_right'), + SqlEquationOperator::NOT_IN => $qb->expr()->notIn($operand, ':eq_right'), SqlEquationOperator::IS_NULL => $qb->expr()->isNull($operand), SqlEquationOperator::IS_NOT_NULL => $qb->expr()->isNotNull($operand), - default => null, + default => null, // keep this for future operators that might be added to the enum }; if (!$where) { @@ -111,4 +113,4 @@ public static function define( return $definition; } -} \ No newline at end of file +} From fef6518a2c24daf4f15b4d04a9e551ef5526403a Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Mon, 7 Sep 2026 15:16:29 +0200 Subject: [PATCH 3/5] Fix typo in parentheses placement for operator validation in SimpleEquationMod --- src/Engine/Mod/SimpleEquationMod.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Engine/Mod/SimpleEquationMod.php b/src/Engine/Mod/SimpleEquationMod.php index fefb9892..8d866618 100644 --- a/src/Engine/Mod/SimpleEquationMod.php +++ b/src/Engine/Mod/SimpleEquationMod.php @@ -18,8 +18,8 @@ public static function getType(): string public function __invoke(Engine $engine, array $options): void { - $operator = SqlEquationOperator::match($options['operator'] - ?? throw new \InvalidArgumentException('Invalid equation operator provided')); + $operator = SqlEquationOperator::match($options['operator']) + ?? throw new \InvalidArgumentException('Invalid equation operator provided'); $filter = SimpleEquationElement::define( equationLeft: $options['operand1'], From 1d8010fcd6ada9399955a101be485942a0b680a4 Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Mon, 7 Sep 2026 15:18:41 +0200 Subject: [PATCH 4/5] Silence PHPStan always-true match arm in SimpleEquationElement Adding IN/NOT_IN made the operator match exhaustive, so PHPStan flagged the last enum arm as an always-true comparison and the trailing default arm as redundant. Keep the default arm as a runtime safety net for operators added to the enum later and ignore the error inline. --- src/FilterElement/SimpleEquationElement.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/FilterElement/SimpleEquationElement.php b/src/FilterElement/SimpleEquationElement.php index a6091dba..76e71aec 100644 --- a/src/FilterElement/SimpleEquationElement.php +++ b/src/FilterElement/SimpleEquationElement.php @@ -47,8 +47,10 @@ public function __invoke(FilterInvocation $inv, FilterQueryBuilder $qb): void SqlEquationOperator::IN => $qb->expr()->in($operand, ':eq_right'), SqlEquationOperator::NOT_IN => $qb->expr()->notIn($operand, ':eq_right'), SqlEquationOperator::IS_NULL => $qb->expr()->isNull($operand), + // the default arm below is a runtime safety net for operators added to the enum later + // @phpstan-ignore match.alwaysTrue SqlEquationOperator::IS_NOT_NULL => $qb->expr()->isNotNull($operand), - default => null, // keep this for future operators that might be added to the enum + default => null, }; if (!$where) { From 86092e4fea5e167f4572ffebbc6ebb24b837b3d7 Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Mon, 7 Sep 2026 15:24:47 +0200 Subject: [PATCH 5/5] Refactor filter source handling in FilterExecutor and related classes --- src/Engine/Projector/InteractiveProjector.php | 4 +--- src/Model/FilterModel.php | 4 ++-- src/Query/Executor/FilterExecutor.php | 4 +--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Engine/Projector/InteractiveProjector.php b/src/Engine/Projector/InteractiveProjector.php index 662ff34f..29edf78b 100644 --- a/src/Engine/Projector/InteractiveProjector.php +++ b/src/Engine/Projector/InteractiveProjector.php @@ -163,13 +163,11 @@ private function hydrateForm(FormInterface $form, ListSpecification $list): void } catch (OutOfBoundsException $exception) { - $filterSourceId = $filterDefinition->getDataSource()->getFilterIdentifier(); - throw new FlareException( message: 'Filter form does not contain field: ' . $filterName, previous: $exception, method: __METHOD__, - source: $filterSourceId ? \sprintf('tl_flare_filter.id=%s', $filterSourceId) : 'filter inlined' + source: $filterDefinition->getDataSource()?->getFilterIdentifier() ?? 'filter inlined' ); } diff --git a/src/Model/FilterModel.php b/src/Model/FilterModel.php index 38b59ecd..1336431c 100644 --- a/src/Model/FilterModel.php +++ b/src/Model/FilterModel.php @@ -24,7 +24,7 @@ class FilterModel extends Model implements FilterDataSourceInterface, PtableInfe public function getFilterIdentifier(): string { - return (string) $this->id; + return \sprintf('%s.id=%s', static::$strTable, $this->id); } public function getFilterType(): string @@ -116,4 +116,4 @@ public function __get($strKey) default => parent::__get($strKey), }; } -} \ No newline at end of file +} diff --git a/src/Query/Executor/FilterExecutor.php b/src/Query/Executor/FilterExecutor.php index daa33f64..0fa014bb 100644 --- a/src/Query/Executor/FilterExecutor.php +++ b/src/Query/Executor/FilterExecutor.php @@ -177,9 +177,7 @@ private function createCallbackException( return new FilterException( \sprintf('[FLARE] Query denied: %s / Callback: %s', $e->getMessage(), $errorMethod), code: $e->getCode(), previous: $e, method: $errorMethod, - source: $filter->getDataSource() - ? \sprintf('tl_flare_filter.id=%s', $filter->getDataSource()->getFilterIdentifier() ?: '0') - : null, + source: $filter->getDataSource()?->getFilterIdentifier() ?? 'filter inlined', ); } }