diff --git a/mailpoet/lib/Automation/Engine/Control/FilterHandler.php b/mailpoet/lib/Automation/Engine/Control/FilterHandler.php index b1ecab7d63..ee709f839f 100644 --- a/mailpoet/lib/Automation/Engine/Control/FilterHandler.php +++ b/mailpoet/lib/Automation/Engine/Control/FilterHandler.php @@ -3,6 +3,7 @@ namespace MailPoet\Automation\Engine\Control; use MailPoet\Automation\Engine\Data\Filter as FilterData; +use MailPoet\Automation\Engine\Data\FilterGroup; use MailPoet\Automation\Engine\Data\StepRunArgs; use MailPoet\Automation\Engine\Exceptions; use MailPoet\Automation\Engine\Registry; @@ -19,18 +20,33 @@ class FilterHandler { public function matchesFilters(StepRunArgs $args): bool { $filters = $args->getStep()->getFilters(); - $groups = $filters ? $filters->getGroups() : []; - foreach ($groups as $group) { - foreach ($group->getFilters() as $filter) { - $value = $args->getFieldValue($filter->getFieldKey()); - if (!$this->matchesFilter($filter, $value)) { - return false; - } + if (!$filters) { + return true; + } + + foreach ($filters->getGroups() as $group) { + if ($this->matchesGroup($group, $args)) { + return false; } } return true; } + private function matchesGroup(FilterGroup $group, StepRunArgs $args): bool { + $operator = $group->getOperator(); + foreach ($group->getFilters() as $filter) { + $value = $args->getFieldValue($filter->getFieldKey()); + $matches = $this->matchesFilter($filter, $value); + if ($operator === FilterGroup::OPERATOR_AND && !$matches) { + return false; + } + if ($operator === FilterGroup::OPERATOR_OR && $matches) { + return true; + } + } + return $operator === FilterGroup::OPERATOR_AND; + } + /** @param mixed $value */ private function matchesFilter(FilterData $data, $value): bool { $filter = $this->registry->getFilter($data->getFieldType()); diff --git a/mailpoet/tests/unit/Automation/Engine/Control/FilterHandlerTest.php b/mailpoet/tests/unit/Automation/Engine/Control/FilterHandlerTest.php index 391f5f33bc..865ff699a5 100644 --- a/mailpoet/tests/unit/Automation/Engine/Control/FilterHandlerTest.php +++ b/mailpoet/tests/unit/Automation/Engine/Control/FilterHandlerTest.php @@ -59,6 +59,32 @@ class FilterHandlerTest extends MailPoetUnitTest { $this->assertSame($expectation, $result); } + /** @dataProvider dataForTestItEvaluatesGroupOperators */ + public function testItEvaluatesGroupOperators(FilterGroup $group, bool $expectation): void { + $filters = new Filters('and', [$group]); + $step = new Step('step', Step::TYPE_TRIGGER, 'test:step', [], [], $filters); + $subject = $this->createSubject('subject', [ + new Field('test:field-string', Field::TYPE_STRING, 'Test field string', function () { + return 'abc'; + }), + ]); + + $stepRunArgs = new StepRunArgs( + $this->createMock(Automation::class), + $this->createMock(AutomationRun::class), + $step, + [new SubjectEntry($subject, new SubjectData($subject->getKey(), []))] + ); + + $registry = Stub::make(Registry::class, [ + 'filters' => [Field::TYPE_STRING => $this->createFilter(Field::TYPE_STRING)], + ]); + + $handler = new FilterHandler($registry); + $result = $handler->matchesFilters($stepRunArgs); + $this->assertSame($expectation, $result); + } + public function dataForTestItFilters(): array { return [ // no filters @@ -94,6 +120,41 @@ class FilterHandlerTest extends MailPoetUnitTest { ]; } + public function dataForTestItEvaluatesGroupOperators(): array { + return [ + [ + new FilterGroup('g1', 'and', [ + new FilterData('f1', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'abc']), + new FilterData('f2', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'abc']), + new FilterData('f3', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'abc']), + ]), + true, + ], + [ + new FilterGroup('g2', 'and', [ + new FilterData('f1', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'abc']), + new FilterData('f2', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'xyz']), + ]), + false, + ], + [ + new FilterGroup('g3', 'or', [ + new FilterData('f1', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'def']), + new FilterData('f2', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'abc']), + new FilterData('f2', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'xyz']), + ]), + true, + ], + [ + new FilterGroup('g4', 'or', [ + new FilterData('f1', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'def']), + new FilterData('f2', Field::TYPE_STRING, 'test:field-string', '', ['value' => 'xyz']), + ]), + false, + ], + ]; + } + /** @return Subject */ private function createSubject(string $key, array $fields): Subject { return new class($key, $fields) implements Subject {