Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 29 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
| ConditionEvaluator | |
0.00% |
0 / 29 |
|
0.00% |
0 / 4 |
992 | |
0.00% |
0 / 1 |
| passes | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
| flatten | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
30 | |||
| evaluate | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
462 | |||
| isAssoc | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace ImovelZapAi\Automation\Application\Services; |
| 6 | |
| 7 | use ImovelZapAi\Automation\Domain\Enums\ConditionOperator; |
| 8 | use ImovelZapAi\Automation\Infrastructure\Persistence\Eloquent\AutomationConditionModel; |
| 9 | |
| 10 | final class ConditionEvaluator |
| 11 | { |
| 12 | /** |
| 13 | * @param iterable<AutomationConditionModel> $conditions |
| 14 | * @param array<string, mixed> $context |
| 15 | */ |
| 16 | public function passes(iterable $conditions, array $context): bool |
| 17 | { |
| 18 | $flat = $this->flatten($context); |
| 19 | |
| 20 | foreach ($conditions as $condition) { |
| 21 | if (! $this->evaluate($condition, $flat)) { |
| 22 | return false; |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | return true; |
| 27 | } |
| 28 | |
| 29 | /** |
| 30 | * @param array<string, mixed> $context |
| 31 | * @return array<string, mixed> |
| 32 | */ |
| 33 | public function flatten(array $context, string $prefix = ''): array |
| 34 | { |
| 35 | $result = []; |
| 36 | |
| 37 | foreach ($context as $key => $value) { |
| 38 | $path = $prefix === '' ? (string) $key : "{$prefix}.{$key}"; |
| 39 | |
| 40 | if (is_array($value) && $this->isAssoc($value)) { |
| 41 | $result += $this->flatten($value, $path); |
| 42 | } else { |
| 43 | $result[$path] = $value; |
| 44 | $result[(string) $key] = $value; |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | return $result; |
| 49 | } |
| 50 | |
| 51 | /** |
| 52 | * @param array<string, mixed> $flat |
| 53 | */ |
| 54 | private function evaluate(AutomationConditionModel $condition, array $flat): bool |
| 55 | { |
| 56 | $actual = $flat[$condition->field] ?? null; |
| 57 | $expected = $condition->value; |
| 58 | |
| 59 | return match ($condition->operator) { |
| 60 | ConditionOperator::Eq => (string) $actual === (string) $expected, |
| 61 | ConditionOperator::Neq => (string) $actual !== (string) $expected, |
| 62 | ConditionOperator::Gt => is_numeric($actual) && is_numeric($expected) && (float) $actual > (float) $expected, |
| 63 | ConditionOperator::Gte => is_numeric($actual) && is_numeric($expected) && (float) $actual >= (float) $expected, |
| 64 | ConditionOperator::Lt => is_numeric($actual) && is_numeric($expected) && (float) $actual < (float) $expected, |
| 65 | ConditionOperator::Lte => is_numeric($actual) && is_numeric($expected) && (float) $actual <= (float) $expected, |
| 66 | ConditionOperator::Contains => is_string($actual) && is_string($expected) && str_contains($actual, $expected), |
| 67 | ConditionOperator::In => in_array((string) $actual, array_map('trim', explode(',', (string) $expected)), true), |
| 68 | ConditionOperator::Exists => $actual !== null && $actual !== '', |
| 69 | }; |
| 70 | } |
| 71 | |
| 72 | /** @param array<mixed> $value */ |
| 73 | private function isAssoc(array $value): bool |
| 74 | { |
| 75 | if ($value === []) { |
| 76 | return false; |
| 77 | } |
| 78 | |
| 79 | return array_keys($value) !== range(0, count($value) - 1); |
| 80 | } |
| 81 | } |