Passed
Push — master ( f70a09...b9b259 )
by SignpostMarv
05:56
created

RecallDaftNestedObjectPathToId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 20
ccs 6
cts 6
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
* Base daft objects.
4
*
5
* @author SignpostMarv
6
*/
7
declare(strict_types=1);
8
9
namespace SignpostMarv\DaftObject;
10
11
/**
12
* @template T as DaftNestedObject
13
*
14
* @template-extends DaftObjectMemoryRepository<T>
15
*
16
* @template-implements DaftNestedObjectTree<T>
17
*/
18
abstract class DaftObjectMemoryTree extends DaftObjectMemoryRepository implements DaftNestedObjectTree
19
{
20
    const DECREMENT = -1;
21
22
    const INCREMENT = 1;
23
24
    const BOOL_DEFAULT_ASSUME_DOES_NOT_EXIST = false;
25
26
    const INT_ARG_INDEX_FIRST = 1;
27
28
    const BOOL_DEFAULT_NO_MODIFY = 0;
29
30
    /**
31
    * {@inheritdoc}
32
    *
33
    * @psalm-return T
34
    */
35 62
    public function RecallDaftNestedObjectOrThrow($id) : DaftNestedObject
36
    {
37
        /**
38
        * @var DaftNestedObject|null
39
        *
40
        * @psalm-var T|null
41
        */
42 62
        $out = $this->RecallDaftObject($id);
43
44 62
        if (is_null($out)) {
45 14
            throw new DaftObjectNotRecalledException(
46
                'Argument 1 passed to ' .
47
                DaftNestedObjectTree::class .
48
                '::RecallDaftNestedObjectOrThrow() did not resolve to an instance of ' .
49
                DaftNestedObject::class .
50
                ' from ' .
51 14
                static::class .
52 14
                '::RecallDaftObject()'
53
            );
54
        }
55
56 60
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out returns the type SignpostMarv\DaftObject\SuitableForRepositoryType which includes types incompatible with the type-hinted return SignpostMarv\DaftObject\DaftNestedObject.
Loading history...
57
    }
58
59 90
    public function RecallDaftNestedObjectFullTree(int $relativeDepthLimit = null) : array
60
    {
61
        /**
62
        * @var array<int, DaftNestedObject>
63
        */
64 90
        $out = $this->memory;
65
66 90
        $outIds = [];
67
68 90
        foreach ($out as $obj) {
69
            /**
70
            * @var array<int, scalar|(scalar|array|object|null)[]>
71
            */
72 44
            $id = $obj->GetId();
73
74 44
            $outIds[] = $id;
75
        }
76
77
        /**
78
        * @var array<int, DaftNestedObject>
79
        *
80
        * @psalm-var array<int, T>
81
        */
82 90
        $fromMemory = array_filter(
83 90
            array_map([$this, 'MapDataToObject'], $this->data),
84
            function (DaftNestedObject $leaf) use ($outIds) : bool {
85 64
                return ! in_array($leaf->GetId(), $outIds, true);
86 90
            }
87
        );
88
89 90
        $out = array_merge($out, $fromMemory);
90
91 90
        usort(
92 90
            $out,
93
            /**
94
            * @psalm-param T $a
95
            * @psalm-param T $b
96
            */
97
            function (DaftNestedObject $a, DaftNestedObject $b) : int {
98 64
                return $a->GetIntNestedLeft() <=> $b->GetIntNestedLeft();
99 90
            }
100
        );
101
102 90
        if (is_int($relativeDepthLimit)) {
103
            $filter =
104
                /**
105
                * @psalm-param T $e
106
                */
107
                function (DaftNestedObject $e) use ($relativeDepthLimit) : bool {
108 32
                    return $e->GetIntNestedLevel() <= $relativeDepthLimit;
109 32
                };
110 32
            $out = array_filter($out, $filter);
111
        }
112
113 90
        return $out;
114
    }
115
116 90
    public function CountDaftNestedObjectFullTree(int $relativeDepthLimit = null) : int
117
    {
118 90
        return count($this->RecallDaftNestedObjectFullTree($relativeDepthLimit));
119
    }
120
121
    /**
122
    * {@inheritdoc}
123
    *
124
    * @psalm-param T $root
125
    *
126
    * @psalm-return array<int, T>
127
    */
128 44
    public function RecallDaftNestedObjectTreeWithObject(
129
        DaftNestedObject $root,
130
        bool $includeRoot,
131
        ? int $limit
132
    ) : array {
133 44
        $left = $root->GetIntNestedLeft();
134 44
        $right = $root->GetIntNestedRight();
135 44
        $limit = is_int($limit) ? ($root->GetIntNestedLevel() + $limit) : null;
136
137 44
        $leaves = $this->RecallDaftNestedObjectFullTree();
138
139 44
        if (is_int($limit)) {
140
            $leaves = array_filter($leaves, function (DaftNestedObject $e) use ($limit) : bool {
141 38
                return $e->GetIntNestedLevel() <= $limit;
142 38
            });
143
        }
144
145 44
        return array_values(array_filter(
146 44
            $leaves,
147
            /**
148
            * @psalm-param T $e
149
            */
150
            function (DaftNestedObject $e) use ($includeRoot, $left, $right) : bool {
151 44
                return $this->FilterLeaf($includeRoot, $left, $right, $e);
152 44
            }
153
        ));
154
    }
155
156
    /**
157
    * @psalm-param T $root
158
    */
159 20
    public function CountDaftNestedObjectTreeWithObject(
160
        DaftNestedObject $root,
161
        bool $includeRoot,
162
        ? int $relativeDepthLimit
163
    ) : int {
164 20
        return count(
165 20
            $this->RecallDaftNestedObjectTreeWithObject($root, $includeRoot, $relativeDepthLimit)
166
        );
167
    }
168
169
    /**
170
    * @param scalar|(scalar|array|object|null)[] $id
171
    *
172
    * @return array<int, DaftNestedObject>
173
    */
174 56
    public function RecallDaftNestedObjectTreeWithId(
175
        $id,
176
        bool $includeRoot,
177
        ? int $relativeDepthLimit
178
    ) : array {
179
        /**
180
        * @psalm-var T|null
181
        */
182 56
        $object = $this->RecallDaftObject($id);
183
184
        /**
185
        * @var array<int, DaftNestedObject>
186
        *
187
        * @psalm-var array<int, T>
188
        */
189
        $out =
190 56
            ($object instanceof DaftNestedObject)
191 28
                ? $this->RecallDaftNestedObjectTreeWithObject(
192 28
                    $object,
193 28
                    $includeRoot,
194 28
                    $relativeDepthLimit
195
                )
196
                : (
197 32
                    ((array) $id === (array) $this->GetNestedObjectTreeRootId())
198 32
                        ? $this->RecallDaftNestedObjectFullTree($relativeDepthLimit)
199 56
                        : []
200
                );
201
202 56
        return $out;
203
    }
204
205
    /**
206
    * @param scalar|(scalar|array|object|null)[] $id
207
    */
208 4
    public function CountDaftNestedObjectTreeWithId(
209
        $id,
210
        bool $includeRoot,
211
        ? int $relativeDepthLimit
212
    ) : int {
213 4
        return count($this->RecallDaftNestedObjectTreeWithId(
214 4
            $id,
215 4
            $includeRoot,
216 4
            $relativeDepthLimit
217
        ));
218
    }
219
220
    /**
221
    * @psalm-param T $leaf
222
    *
223
    * @return array<int, DaftNestedObject>
224
    *
225
    * @psalm-return array<int, T>
226
    */
227 4
    public function RecallDaftNestedObjectPathToObject(
228
        DaftNestedObject $leaf,
229
        bool $includeLeaf
230
    ) : array {
231
        $left =
232 4
            $leaf->GetIntNestedLeft() +
233 4
            ($includeLeaf ? self::BOOL_DEFAULT_NO_MODIFY : self::DECREMENT);
234
        $right =
235 4
            $leaf->GetIntNestedRight() +
236 4
            ($includeLeaf ? self::BOOL_DEFAULT_NO_MODIFY : self::INCREMENT);
237
238
        /**
239
        * @var array<int, DaftNestedObject>
240
        *
241
        * @psalm-var array<int, T>
242
        */
243 4
        $out = array_values(array_filter(
244 4
            $this->RecallDaftNestedObjectFullTree(),
245
            function (DaftNestedObject $e) use ($left, $right) : bool {
246 4
                return $e->GetIntNestedLeft() <= $left && $e->GetIntNestedRight() >= $right;
247 4
            }
248
        ));
249
250 4
        return $out;
251
    }
252
253
    /**
254
    * @psalm-param T $leaf
255
    */
256 4
    public function CountDaftNestedObjectPathToObject(
257
        DaftNestedObject $leaf,
258
        bool $includeLeaf
259
    ) : int {
260 4
        return count($this->RecallDaftNestedObjectPathToObject($leaf, $includeLeaf));
261
    }
262
263
    /**
264
    * @param scalar|(scalar|array|object|null)[] $id
265
    *
266
    * @return array<int, DaftNestedObject>
267
    *
268
    * @psalm-return array<int, T>
269
    */
270 4
    public function RecallDaftNestedObjectPathToId($id, bool $includeLeaf) : array
271
    {
272
        /**
273
        * @var DaftNestedObject|null
274
        *
275
        * @psalm-var T|null
276
        */
277 4
        $object = $this->RecallDaftObject($id);
278
279
        /**
280
        * @var array<int, DaftNestedObject>
281
        *
282
        * @psalm-var array<int, T>
283
        */
284
        $out =
285 4
            ($object instanceof DaftNestedObject)
286 4
                ? $this->RecallDaftNestedObjectPathToObject($object, $includeLeaf)
287 4
                : [];
288
289 4
        return $out;
290
    }
291
292
    /**
293
    * @param scalar|(scalar|array|object|null)[] $id
294
    */
295 4
    public function CountDaftNestedObjectPathToId($id, bool $includeLeaf) : int
296
    {
297 4
        return count($this->RecallDaftNestedObjectPathToId($id, $includeLeaf));
298
    }
299
300
    /**
301
    * @psalm-param T $object
302
    */
303 94
    public function RememberDaftObject(SuitableForRepositoryType $object) : void
304
    {
305 94
        parent::RememberDaftObject($object);
306 94
    }
307
308
    /**
309
    * {@inheritdoc}
310
    *
311
    * @psalm-return T|null
312
    */
313 68
    public function RecallDaftObject($id) : ? SuitableForRepositoryType
314
    {
315 68
        return parent::RecallDaftObject($id);
316
    }
317
318
    /**
319
    * @psalm-return T
320
    */
321 64
    private function MapDataToObject(array $row) : DaftNestedObject
322
    {
323
        /**
324
        * @psalm-var class-string<T>
325
        */
326 64
        $type = $this->type;
327
328
        /**
329
        * @var DaftNestedObject
330
        *
331
        * @psalm-var T
332
        */
333 64
        $out = new $type($row);
334
335 64
        return $out;
336
    }
337
338
    /**
339
    * @psalm-param T $e
340
    */
341 44
    private function FilterLeaf(
342
        bool $includeRoot,
343
        int $left,
344
        int $right,
345
        DaftNestedObject $e
346
    ) : bool {
347 44
        if ($includeRoot) {
348 4
            return $e->GetIntNestedLeft() >= $left && $e->GetIntNestedRight() <= $right;
349
        }
350
351 44
        return $e->GetIntNestedLeft() > $left && $e->GetIntNestedRight() < $right;
352
    }
353
}
354