Passed
Push — master ( b7f313...3401c7 )
by SignpostMarv
06:04
created

  A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 1
dl 0
loc 22
ccs 7
cts 7
cp 1
crap 2
rs 9.9
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 90
    public function RecallDaftNestedObjectFullTree(int $relativeDepthLimit = null) : array
31
    {
32
        /**
33
        * @var array<int, DaftNestedObject>
34
        */
35 90
        $out = $this->memory;
36
37 90
        $outIds = [];
38
39 90
        foreach ($out as $obj) {
40
            /**
41
            * @var array<int, scalar|(scalar|array|object|null)[]>
42
            */
43 44
            $id = $obj->GetId();
44
45 44
            $outIds[] = $id;
46
        }
47
48
        /**
49
        * @var array<int, DaftNestedObject>
50
        *
51
        * @psalm-var array<int, T>
52
        */
53 90
        $fromMemory = array_filter(
54 90
            array_map([$this, 'MapDataToObject'], $this->data),
55
            function (DaftNestedObject $leaf) use ($outIds) : bool {
56 64
                return ! in_array($leaf->GetId(), $outIds, true);
57 90
            }
58
        );
59
60 90
        $out = array_merge($out, $fromMemory);
61
62 90
        usort(
63 90
            $out,
64
            /**
65
            * @psalm-param T $a
66
            * @psalm-param T $b
67
            */
68
            function (DaftNestedObject $a, DaftNestedObject $b) : int {
69 64
                return $a->GetIntNestedLeft() <=> $b->GetIntNestedLeft();
70 90
            }
71
        );
72
73 90
        if (is_int($relativeDepthLimit)) {
74
            $filter =
75
                /**
76
                * @psalm-param T $e
77
                */
78
                function (DaftNestedObject $e) use ($relativeDepthLimit) : bool {
79 32
                    return $e->GetIntNestedLevel() <= $relativeDepthLimit;
80 32
                };
81 32
            $out = array_filter($out, $filter);
82
        }
83
84 90
        return $out;
85
    }
86
87 90
    public function CountDaftNestedObjectFullTree(int $relativeDepthLimit = null) : int
88
    {
89 90
        return count($this->RecallDaftNestedObjectFullTree($relativeDepthLimit));
90
    }
91
92
    /**
93
    * {@inheritdoc}
94
    *
95
    * @psalm-param T $root
96
    *
97
    * @psalm-return array<int, T>
98
    */
99 44
    public function RecallDaftNestedObjectTreeWithObject(
100
        DaftNestedObject $root,
101
        bool $includeRoot,
102
        ? int $limit
103
    ) : array {
104 44
        $left = $root->GetIntNestedLeft();
105 44
        $right = $root->GetIntNestedRight();
106 44
        $limit = is_int($limit) ? ($root->GetIntNestedLevel() + $limit) : null;
107
108 44
        $leaves = $this->RecallDaftNestedObjectFullTree();
109
110 44
        if (is_int($limit)) {
111
            $leaves = array_filter($leaves, function (DaftNestedObject $e) use ($limit) : bool {
112 38
                return $e->GetIntNestedLevel() <= $limit;
113 38
            });
114
        }
115
116 44
        return array_values(array_filter(
117 44
            $leaves,
118
            /**
119
            * @psalm-param T $e
120
            */
121
            function (DaftNestedObject $e) use ($includeRoot, $left, $right) : bool {
122 44
                return $this->FilterLeaf($includeRoot, $left, $right, $e);
123 44
            }
124
        ));
125
    }
126
127
    /**
128
    * @psalm-param T $root
129
    */
130 20
    public function CountDaftNestedObjectTreeWithObject(
131
        DaftNestedObject $root,
132
        bool $includeRoot,
133
        ? int $relativeDepthLimit
134
    ) : int {
135 20
        return count(
136 20
            $this->RecallDaftNestedObjectTreeWithObject($root, $includeRoot, $relativeDepthLimit)
137
        );
138
    }
139
140
    /**
141
    * @param scalar|(scalar|array|object|null)[] $id
142
    *
143
    * @return array<int, DaftNestedObject>
144
    *
145
    * @psalm-return array<int, T>
146
    */
147 56
    public function RecallDaftNestedObjectTreeWithId(
148
        $id,
149
        bool $includeRoot,
150
        ? int $relativeDepthLimit
151
    ) : array {
152
        /**
153
        * @psalm-var T|null
154
        */
155 56
        $object = $this->RecallDaftObject($id);
156
157
        /**
158
        * @var array<int, DaftNestedObject>
159
        *
160
        * @psalm-var array<int, T>
161
        */
162
        $out =
163 56
            ($object instanceof DaftNestedObject)
164 28
                ? $this->RecallDaftNestedObjectTreeWithObject(
165 28
                    $object,
166 28
                    $includeRoot,
167 28
                    $relativeDepthLimit
168
                )
169
                : (
170 32
                    ((array) $id === (array) $this->GetNestedObjectTreeRootId())
171 32
                        ? $this->RecallDaftNestedObjectFullTree($relativeDepthLimit)
172 56
                        : []
173
                );
174
175 56
        return $out;
176
    }
177
178
    /**
179
    * @param scalar|(scalar|array|object|null)[] $id
180
    */
181 4
    public function CountDaftNestedObjectTreeWithId(
182
        $id,
183
        bool $includeRoot,
184
        ? int $relativeDepthLimit
185
    ) : int {
186 4
        return count($this->RecallDaftNestedObjectTreeWithId(
187 4
            $id,
188 4
            $includeRoot,
189 4
            $relativeDepthLimit
190
        ));
191
    }
192
193
    /**
194
    * @psalm-param T $leaf
195
    *
196
    * @return array<int, DaftNestedObject>
197
    *
198
    * @psalm-return array<int, T>
199
    */
200 4
    public function RecallDaftNestedObjectPathToObject(
201
        DaftNestedObject $leaf,
202
        bool $includeLeaf
203
    ) : array {
204
        $left =
205 4
            $leaf->GetIntNestedLeft() +
206 4
            ($includeLeaf ? self::BOOL_DEFAULT_NO_MODIFY : self::DECREMENT);
207
        $right =
208 4
            $leaf->GetIntNestedRight() +
209 4
            ($includeLeaf ? self::BOOL_DEFAULT_NO_MODIFY : self::INCREMENT);
210
211
        /**
212
        * @var array<int, DaftNestedObject>
213
        *
214
        * @psalm-var array<int, T>
215
        */
216 4
        $out = array_values(array_filter(
217 4
            $this->RecallDaftNestedObjectFullTree(),
218
            function (DaftNestedObject $e) use ($left, $right) : bool {
219 4
                return $e->GetIntNestedLeft() <= $left && $e->GetIntNestedRight() >= $right;
220 4
            }
221
        ));
222
223 4
        return $out;
224
    }
225
226
    /**
227
    * @psalm-param T $leaf
228
    */
229 4
    public function CountDaftNestedObjectPathToObject(
230
        DaftNestedObject $leaf,
231
        bool $includeLeaf
232
    ) : int {
233 4
        return count($this->RecallDaftNestedObjectPathToObject($leaf, $includeLeaf));
234
    }
235
236
    /**
237
    * @param scalar|(scalar|array|object|null)[] $id
238
    *
239
    * @return array<int, DaftNestedObject>
240
    *
241
    * @psalm-return array<int, T>
242
    */
243 4
    public function RecallDaftNestedObjectPathToId($id, bool $includeLeaf) : array
244
    {
245
        /**
246
        * @var DaftNestedObject|null
247
        *
248
        * @psalm-var T|null
249
        */
250 4
        $object = $this->RecallDaftObject($id);
251
252
        /**
253
        * @var array<int, DaftNestedObject>
254
        *
255
        * @psalm-var array<int, T>
256
        */
257
        $out =
258 4
            ($object instanceof DaftNestedObject)
259 4
                ? $this->RecallDaftNestedObjectPathToObject($object, $includeLeaf)
260 4
                : [];
261
262 4
        return $out;
263
    }
264
265
    /**
266
    * @param scalar|(scalar|array|object|null)[] $id
267
    */
268 4
    public function CountDaftNestedObjectPathToId($id, bool $includeLeaf) : int
269
    {
270 4
        return count($this->RecallDaftNestedObjectPathToId($id, $includeLeaf));
271
    }
272
273
    /**
274
    * @psalm-param T $object
275
    */
276 94
    public function RememberDaftObject(SuitableForRepositoryType $object) : void
277
    {
278 94
        parent::RememberDaftObject($object);
279 94
    }
280
281
    /**
282
    * {@inheritdoc}
283
    *
284
    * @psalm-return T|null
285
    */
286 68
    public function RecallDaftObject($id) : ? SuitableForRepositoryType
287
    {
288 68
        return parent::RecallDaftObject($id);
289
    }
290
291
    /**
292
    * @psalm-return T
293
    */
294 64
    private function MapDataToObject(array $row) : DaftNestedObject
295
    {
296
        /**
297
        * @psalm-var class-string<T>
298
        */
299 64
        $type = $this->type;
300
301
        /**
302
        * @var DaftNestedObject
303
        *
304
        * @psalm-var T
305
        */
306 64
        $out = new $type($row);
307
308 64
        return $out;
309
    }
310
311
    /**
312
    * @psalm-param T $e
313
    */
314 44
    private function FilterLeaf(
315
        bool $includeRoot,
316
        int $left,
317
        int $right,
318
        DaftNestedObject $e
319
    ) : bool {
320 44
        if ($includeRoot) {
321 4
            return $e->GetIntNestedLeft() >= $left && $e->GetIntNestedRight() <= $right;
322
        }
323
324 44
        return $e->GetIntNestedLeft() > $left && $e->GetIntNestedRight() < $right;
325
    }
326
}
327