Evaluator::evaluateLiteralValues()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 2
dl 0
loc 17
ccs 10
cts 10
cp 1
crap 3
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\JSON\Path\Runtime;
6
7
use Remorhaz\JSON\Data\Comparator\ComparatorInterface;
8
use Remorhaz\JSON\Path\Value\EvaluatedValueList;
9
use Remorhaz\JSON\Path\Value\EvaluatedValueListBuilder;
10
use Remorhaz\JSON\Path\Value\EvaluatedValueListInterface;
11
use Remorhaz\JSON\Path\Value\IndexMapInterface;
12
use Remorhaz\JSON\Path\Value\LiteralValueListInterface;
13
use Remorhaz\JSON\Data\Value\ScalarValueInterface;
14
use Remorhaz\JSON\Path\Value\ValueListBuilder;
15
use Remorhaz\JSON\Path\Value\ValueListInterface;
16
17
use function array_fill;
18
use function count;
19
use function is_bool;
20
use function preg_match;
21
22
final class Evaluator implements EvaluatorInterface
23
{
24
25
    private $comparators;
26
27
    private $aggregators;
28
29 52
    public function __construct(
30
        ComparatorCollectionInterface $comparators,
31
        Aggregator\AggregatorCollectionInterface $aggregators
32
    ) {
33 52
        $this->comparators = $comparators;
34 52
        $this->aggregators = $aggregators;
35 52
    }
36
37 6
    public function logicalOr(
38
        EvaluatedValueListInterface $leftValues,
39
        EvaluatedValueListInterface $rightValues
40
    ): EvaluatedValueListInterface {
41 6
        $results = [];
42 6
        foreach ($leftValues->getResults() as $index => $leftResult) {
43 4
            $results[] = $leftResult || $rightValues->getResult($index);
44
        }
45
46 6
        return new EvaluatedValueList(
47 6
            $this->getEqualIndexMap($leftValues, $rightValues),
48 5
            ...$results
49
        );
50
    }
51
52 6
    public function logicalAnd(
53
        EvaluatedValueListInterface $leftValues,
54
        EvaluatedValueListInterface $rightValues
55
    ): EvaluatedValueListInterface {
56 6
        $results = [];
57 6
        foreach ($leftValues->getResults() as $index => $leftResult) {
58 4
            $results[] = $leftResult && $rightValues->getResult($index);
59
        }
60
61 6
        return new EvaluatedValueList(
62 6
            $this->getEqualIndexMap($leftValues, $rightValues),
63 5
            ...$results
64
        );
65
    }
66
67 4
    public function logicalNot(EvaluatedValueListInterface $values): EvaluatedValueListInterface
68
    {
69 4
        $results = [];
70 4
        foreach ($values->getResults() as $leftResult) {
71 2
            $results[] = !$leftResult;
72
        }
73
74 4
        return new EvaluatedValueList($values->getIndexMap(), ...$results);
75
    }
76
77 9
    public function isEqual(
78
        ValueListInterface $leftValues,
79
        ValueListInterface $rightValues
80
    ): EvaluatedValueListInterface {
81 9
        return $this->compare(
82 9
            $leftValues,
83
            $rightValues,
84 9
            $this->comparators->equal()
85
        );
86
    }
87
88 5
    public function isGreater(
89
        ValueListInterface $leftValues,
90
        ValueListInterface $rightValues
91
    ): EvaluatedValueListInterface {
92 5
        return $this->compare(
93 5
            $leftValues,
94
            $rightValues,
95 5
            $this->comparators->greater()
96
        );
97
    }
98
99 14
    private function compare(
100
        ValueListInterface $leftValues,
101
        ValueListInterface $rightValues,
102
        ComparatorInterface $comparator
103
    ): EvaluatedValueListInterface {
104 14
        $valueListBuilder = new EvaluatedValueListBuilder();
105 14
        foreach ($leftValues->getIndexMap()->getOuterIndexes() as $leftInnerIndex => $leftOuterIndex) {
106 13
            foreach ($rightValues->getIndexMap()->getOuterIndexes() as $rightInnerIndex => $rightOuterIndex) {
107 13
                if (!isset($leftOuterIndex, $rightOuterIndex)) {
108 3
                    continue;
109
                }
110 10
                if ($leftOuterIndex != $rightOuterIndex) {
111 2
                    continue;
112
                }
113
114 8
                $valueListBuilder->addResult(
115 8
                    $comparator->compare(
116 8
                        $leftValues->getValue($leftInnerIndex),
117 8
                        $rightValues->getValue($rightInnerIndex)
118
                    ),
119
                    $leftOuterIndex
120
                );
121
            }
122
        }
123
124 14
        return $valueListBuilder->build();
125
    }
126
127 7
    public function isRegExp(string $regExp, ValueListInterface $values): EvaluatedValueListInterface
128
    {
129 7
        $results = [];
130
131 7
        foreach ($values->getValues() as $value) {
132 5
            if (!$value instanceof ScalarValueInterface) {
133 1
                $results[] = false;
134 1
                continue;
135
            }
136 4
            $data = $value->getData();
137 4
            if (!is_string($data)) {
138 1
                $results[] = false;
139 1
                continue;
140
            }
141 3
            $match = @preg_match($regExp, $data);
142 3
            if (false === $match) {
143 1
                throw new Exception\InvalidRegExpException($regExp);
144
            }
145 2
            $results[] = 1 === $match;
146
        }
147
148 6
        return new EvaluatedValueList($values->getIndexMap(), ...$results);
149
    }
150
151 9
    public function evaluate(
152
        ValueListInterface $sourceValues,
153
        ValueListInterface $resultValues
154
    ): EvaluatedValueListInterface {
155 9
        if ($resultValues instanceof EvaluatedValueListInterface) {
156 1
            return $resultValues;
157
        }
158
159 8
        if ($resultValues instanceof LiteralValueListInterface) {
160 4
            return $this->evaluateLiteralValues($sourceValues, $resultValues);
161
        }
162
163 4
        $results = [];
164 4
        foreach ($sourceValues->getIndexMap()->getOuterIndexes() as $outerIndex) {
165 3
            $results[] = isset($outerIndex)
166 2
                ? $resultValues->getIndexMap()->outerIndexExists($outerIndex)
167 1
                : false;
168
        }
169
170 4
        return new EvaluatedValueList($sourceValues->getIndexMap(), ...$results);
171
    }
172
173 4
    private function evaluateLiteralValues(
174
        ValueListInterface $sourceValues,
175
        LiteralValueListInterface $resultValues
176
    ): EvaluatedValueListInterface {
177 4
        $indexMap = $this->getEqualIndexMap($sourceValues, $resultValues);
178 4
        $literal = $resultValues->getLiteral();
179 4
        if ($literal instanceof ScalarValueInterface) {
180 3
            $data = $literal->getData();
181 3
            if (is_bool($data)) {
182 2
                return new EvaluatedValueList(
183 2
                    $indexMap,
184 2
                    ...array_fill(0, count($indexMap), $data)
185
                );
186
            }
187
        }
188
189 2
        throw new Exception\LiteralEvaluationFailedException($literal);
190
    }
191
192 16
    private function getEqualIndexMap(
193
        ValueListInterface $leftValues,
194
        ValueListInterface $rightValues
195
    ): IndexMapInterface {
196 16
        $indexMap = $leftValues->getIndexMap();
197 16
        if ($indexMap->equals($rightValues->getIndexMap())) {
198 14
            return $indexMap;
199
        }
200
201 2
        throw new Exception\IndexMapMatchFailedException($leftValues, $rightValues);
202
    }
203
204 6
    public function aggregate(string $functionName, ValueListInterface $values): ValueListInterface
205
    {
206 6
        $aggregator = $this->aggregators->byName($functionName);
207 6
        $valuesBuilder = new ValueListBuilder();
208 6
        foreach ($values->getValues() as $innerIndex => $value) {
209 4
            $aggregatedValue = $aggregator->tryAggregate($value);
210 4
            if (isset($aggregatedValue)) {
211 2
                $valuesBuilder->addValue(
212 2
                    $aggregatedValue,
213 2
                    $values->getIndexMap()->getOuterIndex($innerIndex)
214
                );
215
            }
216
        }
217
218 6
        return $valuesBuilder->build();
219
    }
220
}
221