Completed
Push — master ( 37a545...2ac5c4 )
by Edward
04:29
created

Fetcher::fetchDeepChildren()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 2
dl 0
loc 14
ccs 0
cts 8
cp 0
crap 12
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Remorhaz\JSON\Path\Runtime;
5
6
use function array_push;
7
use Iterator;
8
use Remorhaz\JSON\Data\Value\ArrayValueInterface;
9
use Remorhaz\JSON\Path\Value\EvaluatedValueInterface;
10
use Remorhaz\JSON\Path\Value\EvaluatedValueListInterface;
11
use Remorhaz\JSON\Data\Value\NodeValueInterface;
12
use Remorhaz\JSON\Path\Value\NodeValueListBuilder;
13
use Remorhaz\JSON\Path\Value\NodeValueListInterface;
14
use Remorhaz\JSON\Data\Value\ObjectValueInterface;
15
use Remorhaz\JSON\Data\Value\ScalarValueInterface;
16
use Remorhaz\JSON\Data\Iterator\ValueIteratorFactory;
17
use Remorhaz\JSON\Path\Value\ValueListInterface;
18
19
final class Fetcher
20
{
21
22
    private $valueIteratorFactory;
23
24
    public function __construct(ValueIteratorFactory $valueIteratorFactory)
25
    {
26
        $this->valueIteratorFactory = $valueIteratorFactory;
27
    }
28
29
    /**
30
     * @param NodeValueListInterface $source
31
     * @param Matcher\ChildMatcherInterface ...$matcherList
32
     * @return NodeValueListInterface
33
     */
34
    public function fetchChildren(
35
        NodeValueListInterface $source,
36
        Matcher\ChildMatcherInterface ...$matcherList
37
    ): NodeValueListInterface {
38
        $nodesBuilder = new NodeValueListBuilder;
39
        foreach ($source->getValues() as $sourceIndex => $sourceValue) {
40
            $matcher = $matcherList[$sourceIndex];
41
            $children = $this->fetchValueChildren($matcher, $sourceValue);
42
            $outerIndex = $source->getIndexMap()->getOuterIndex($sourceIndex);
43
            foreach ($children as $child) {
44
                $nodesBuilder->addValue($child, $outerIndex);
45
            }
46
        }
47
48
        return $nodesBuilder->build();
49
    }
50
51
    public function fetchDeepChildren(
52
        Matcher\ChildMatcherInterface $matcher,
53
        NodeValueListInterface $source
54
    ): NodeValueListInterface {
55
        $nodesBuilder = new NodeValueListBuilder;
56
        foreach ($source->getValues() as $sourceIndex => $sourceValue) {
57
            $children = $this->fetchValueDeepChildren($matcher, $sourceValue);
58
            $outerIndex = $source->getIndexMap()->getOuterIndex($sourceIndex);
59
            foreach ($children as $child) {
60
                $nodesBuilder->addValue($child, $outerIndex);
61
            }
62
        }
63
64
        return $nodesBuilder->build();
65
    }
66
67
    /**
68
     * @param Matcher\ChildMatcherInterface $matcher
69
     * @param NodeValueInterface $value
70
     * @return NodeValueInterface[]
71
     */
72
    private function fetchValueChildren(
73
        Matcher\ChildMatcherInterface $matcher,
74
        NodeValueInterface $value
75
    ): array {
76
        if ($value instanceof ScalarValueInterface) {
77
            return [];
78
        }
79
80
        if ($value instanceof ArrayValueInterface) {
81
            return $this->fetchElements($value->createIterator(), $matcher);
82
        }
83
84
        if ($value instanceof ObjectValueInterface) {
85
            return $this->fetchProperties($value->createIterator(), $matcher);
86
        }
87
88
        throw new Exception\UnexpectedNodeValueFetchedException($value);
89
    }
90
91
    private function fetchValueDeepChildren(
92
        Matcher\ChildMatcherInterface $matcher,
93
        NodeValueInterface $value
94
    ): array {
95
        if ($value instanceof ScalarValueInterface) {
96
            return [];
97
        }
98
99
        if ($value instanceof ArrayValueInterface) {
100
            return $this->fetchDeepElements($value->createIterator(), $matcher);
101
        }
102
103
        if ($value instanceof ObjectValueInterface) {
104
            return $this->fetchDeepProperties($value->createIterator(), $matcher);
105
        }
106
107
        throw new Exception\UnexpectedNodeValueFetchedException($value);
108
    }
109
110
    private function fetchDeepElements(Iterator $iterator, Matcher\ChildMatcherInterface $matcher): array
111
    {
112
        $results = [];
113
        foreach ($this->valueIteratorFactory->createArrayIterator($iterator) as $index => $element) {
114
            if ($matcher->match($index)) {
115
                $results[] = $element;
116
            }
117
            array_push(
118
                $results,
119
                ...$this->fetchValueDeepChildren($matcher, $element)
120
            );
121
        }
122
123
        return $results;
124
    }
125
126
    private function fetchDeepProperties(Iterator $iterator, Matcher\ChildMatcherInterface $matcher): array
127
    {
128
        $results = [];
129
        foreach ($this->valueIteratorFactory->createObjectIterator($iterator) as $name => $property) {
130
            if ($matcher->match($name)) {
131
                $results[] = $property;
132
            }
133
            array_push(
134
                $results,
135
                ...$this->fetchValueDeepChildren($matcher, $property)
136
            );
137
        }
138
139
        return $results;
140
    }
141
142
    public function fetchFilterContext(NodeValueListInterface $source): NodeValueListInterface
143
    {
144
        $nodesBuilder = new NodeValueListBuilder;
145
        foreach ($source->getValues() as $sourceIndex => $sourceValue) {
146
            if (!$sourceValue instanceof NodeValueInterface) {
147
                throw new Exception\InvalidContextValueException($sourceValue);
148
            }
149
            $outerIndex = $source->getIndexMap()->getOuterIndex($sourceIndex);
150
            $children = $sourceValue instanceof ArrayValueInterface
151
                ? $this->fetchValueChildren(new Matcher\AnyChildMatcher, $sourceValue)
152
                : [$sourceValue];
153
            foreach ($children as $child) {
154
                $nodesBuilder->addValue($child, $outerIndex);
155
            }
156
        }
157
158
        return $nodesBuilder->build();
159
    }
160
161
    public function fetchFilteredValues(
162
        EvaluatedValueListInterface $results,
163
        NodeValueListInterface $values
164
    ): NodeValueListInterface {
165
        if (!$values->getIndexMap()->equals($results->getIndexMap())) {
166
            throw new Exception\IndexMapMatchFailedException($values, $results);
167
        }
168
        $nodesBuilder = new NodeValueListBuilder;
169
        foreach ($values->getValues() as $index => $value) {
170
            $evaluatedValue = $results->getValue($index);
171
            if (!$evaluatedValue instanceof EvaluatedValueInterface) {
172
                throw new Exception\InvalidFilterValueException($evaluatedValue);
173
            }
174
            if (!$evaluatedValue->getData()) {
175
                continue;
176
            }
177
            $nodesBuilder->addValue(
178
                $value,
179
                $values->getIndexMap()->getOuterIndex($index)
180
            );
181
        }
182
183
        return $nodesBuilder->build();
184
    }
185
186
    private function fetchElements(Iterator $iterator, Matcher\ChildMatcherInterface $matcher): array
187
    {
188
        $results = [];
189
        foreach ($this->valueIteratorFactory->createArrayIterator($iterator) as $index => $element) {
190
            if ($matcher->match($index)) {
191
                $results[] = $element;
192
            }
193
        }
194
195
        return $results;
196
    }
197
198
    private function fetchProperties(Iterator $iterator, Matcher\ChildMatcherInterface $matcher): array
199
    {
200
        $results = [];
201
        foreach ($this->valueIteratorFactory->createObjectIterator($iterator) as $name => $property) {
202
            if ($matcher->match($name)) {
203
                $results[] = $property;
204
            }
205
        }
206
207
        return $results;
208
    }
209
210
    /**
211
     * @param ValueListInterface $valueList
212
     * @return int[][]
213
     */
214
    public function fetchIndice(ValueListInterface $valueList): array
215
    {
216
        $result = [];
217
        foreach ($valueList->getValues() as $valueIndex => $value) {
218
            if (!$value instanceof ArrayValueInterface) {
219
                $result[$valueIndex] = [];
220
                continue;
221
            }
222
223
            $indice = [];
224
            $elementIterator = $this->valueIteratorFactory->createArrayIterator($value->createIterator());
225
            foreach ($elementIterator as $index => $element) {
226
                $indice[] = $index;
227
            }
228
            $result[$valueIndex] = $indice;
229
        }
230
231
        return $result;
232
    }
233
}
234