CountDaftNestedObjectPathToId()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 8
ccs 5
cts 5
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
use PDO;
12
use PDOStatement;
13
14
/**
15
* @template TDbObj as DaftNestedObject
16
*
17
* @template-extends AbstractDaftObjectEasyDBRepository<TDbObj>
18
*
19
* @template-implements DaftNestedObjectTree<TDbObj>
20
*/
21
abstract class AbstractDaftObjectEasyDBTree extends AbstractDaftObjectEasyDBRepository implements DaftNestedObjectTree
22
{
23
    const BOOL_RETRIEVE_WITH_ROOT = false;
24
25
    const INT_LIMIT_ZERO = 0;
26
27
    const DEFAULT_COUNT_IF_NOT_OBJECT = 0;
28
29
    const INT_ARG_INDEX_FIRST = 1;
30
31
    const DEFAULT_BOOL_FETCH_TREE_NOT_PATH = true;
32
33
    /**
34
    * {@inheritdoc}
35
    *
36
    * @psalm-return array<int, TDbObj>
37
    */
38 28
    public function RecallDaftNestedObjectFullTree(int $limit = null) : array
39
    {
40 28
        return $this->RecallDaftNestedObjectTreeFromArgs(
41 28
            null,
42 28
            null,
43 28
            $limit,
44 28
            self::BOOL_RETRIEVE_WITH_ROOT
45
        );
46
    }
47
48 40
    public function CountDaftNestedObjectFullTree(int $withLimit = null) : int
49
    {
50 40
        return $this->CountDaftNestedObjectTreeFromArgs(
51 40
            null,
52 40
            null,
53 40
            $withLimit,
54 40
            self::BOOL_RETRIEVE_WITH_ROOT
55
        );
56
    }
57
58
    /**
59
    * {@inheritdoc}
60
    *
61
    * @psalm-param TDbObj $root
62
    *
63
    * @psalm-return array<int, TDbObj>
64
    */
65 14
    public function RecallDaftNestedObjectTreeWithObject(
66
        DaftNestedObject $root,
67
        bool $withRoot,
68
        ? int $limit
69
    ) : array {
70 14
        $left = $root->GetIntNestedLeft();
71 14
        $right = $root->GetIntNestedRight();
72 14
        $limit = is_int($limit) ? ($root->GetIntNestedLevel() + $limit) : null;
73
74 14
        return $this->RecallDaftNestedObjectTreeFromArgs($left, $right, $limit, $withRoot);
75
    }
76
77
    /**
78
    * {@inheritdoc}
79
    *
80
    * @psalm-param TDbObj $root
81
    */
82 12
    public function CountDaftNestedObjectTreeWithObject(
83
        DaftNestedObject $root,
84
        bool $withRoot,
85
        ? int $limit
86
    ) : int {
87 12
        $left = $root->GetIntNestedLeft();
88 12
        $right = $root->GetIntNestedRight();
89 12
        $limit = is_int($limit) ? ($root->GetIntNestedLevel() + $limit) : null;
90
91 12
        return $this->CountDaftNestedObjectTreeFromArgs($left, $right, $limit, $withRoot);
92
    }
93
94
    /**
95
    * {@inheritdoc}
96
    *
97
    * @psalm-return array<int, TDbObj>
98
    */
99 28
    public function RecallDaftNestedObjectTreeWithId(
100
        $id,
101
        bool $withRoot,
102
        ? int $limit
103
    ) : array {
104
        /**
105
        * @psalm-var TDbObj|null
106
        */
107 28
        $object = $this->RecallDaftObject($id);
108
109
        /**
110
        * @psalm-var array<int, TDbObj>
111
        */
112
        $out =
113 28
            ($object instanceof DaftNestedObject)
114 4
                ? $this->RecallDaftNestedObjectTreeWithObject(
115 4
                    $object,
116 4
                    $withRoot,
117 4
                    $limit
118
                )
119
                : (
120 24
                    ((array) $id === $this->GetNestedObjectTreeRootId())
121 24
                        ? $this->RecallDaftNestedObjectFullTree(self::INT_LIMIT_ZERO)
122 28
                        : []
123
                );
124
125 28
        return $out;
126
    }
127
128
    /**
129
    * {@inheritdoc}
130
    */
131 4
    public function CountDaftNestedObjectTreeWithId(
132
        $id,
133
        bool $withRoot,
134
        ? int $limit
135
    ) : int {
136 4
        $object = $this->RecallDaftObject($id);
137
138
        return
139 4
            ($object instanceof DaftNestedObject)
140 4
                ? $this->CountDaftNestedObjectTreeWithObject(
141 4
                    $object,
142 4
                    $withRoot,
143 4
                    $limit
144
                )
145
                : (
146 4
                    ((array) $id === $this->GetNestedObjectTreeRootId())
147 4
                        ? $this->CountDaftNestedObjectFullTree($limit)
148 4
                        : self::DEFAULT_COUNT_IF_NOT_OBJECT
149
                );
150
    }
151
152
    /**
153
    * {@inheritdoc}
154
    *
155
    * @psalm-param TDbObj $leaf
156
    *
157
    * @psalm-return array<int, TDbObj>
158
    */
159 4
    public function RecallDaftNestedObjectPathToObject(
160
        DaftNestedObject $leaf,
161
        bool $includeLeaf
162
    ) : array {
163 4
        return $this->RecallDaftNestedObjectTreeFromArgs(
164 4
            $leaf->GetIntNestedLeft(),
165 4
            $leaf->GetIntNestedRight(),
166 4
            null,
167 4
            $includeLeaf,
168 4
            false
169
        );
170
    }
171
172
    /**
173
    * {@inheritdoc}
174
    *
175
    * @psalm-param TDbObj $leaf
176
    */
177 4
    public function CountDaftNestedObjectPathToObject(
178
        DaftNestedObject $leaf,
179
        bool $includeLeaf
180
    ) : int {
181 4
        return $this->CountDaftNestedObjectTreeFromArgs(
182 4
            $leaf->GetIntNestedLeft(),
183 4
            $leaf->GetIntNestedRight(),
184 4
            null,
185 4
            $includeLeaf,
186 4
            false
187
        );
188
    }
189
190
    /**
191
    * {@inheritdoc}
192
    *
193
    * @psalm-return array<int, TDbObj>
194
    */
195 4
    public function RecallDaftNestedObjectPathToId($id, bool $includeLeaf) : array
196
    {
197 4
        $object = $this->RecallDaftObject($id);
198
199
        return
200 4
            ($object instanceof DaftNestedObject)
201 4
                ? $this->RecallDaftNestedObjectPathToObject($object, $includeLeaf)
202 4
                : [];
203
    }
204
205
    /**
206
    * {@inheritdoc}
207
    */
208 4
    public function CountDaftNestedObjectPathToId($id, bool $includeLeaf) : int
209
    {
210 4
        $object = $this->RecallDaftObject($id);
211
212
        return
213 4
            ($object instanceof DaftNestedObject)
214 4
                ? $this->CountDaftNestedObjectPathToObject($object, $includeLeaf)
215 4
                : self::DEFAULT_COUNT_IF_NOT_OBJECT;
216
    }
217
218 40
    final protected function SelectingQueryDaftNestedObjectTreeFromArgs(bool $recall) : string
219
    {
220 40
        if ($recall) {
221 28
            $props = $this->type::DaftObjectIdProperties();
222
223 28
            return implode(', ', array_map(
224
                function (string $prop) : string {
225 28
                    return $this->db->escapeIdentifier($prop);
226 28
                },
227 28
                $props
228
            ));
229
        }
230
231 40
        return 'COUNT(*)';
232
    }
233
234
    /**
235
    * @param array<int, string> $filter
236
    */
237 40
    final protected function FilterQueryDaftNestedObjectTreeFromArgs(array $filter) : string
238
    {
239 40
        return (count($filter) > 0) ? (' WHERE ' . implode(' AND ', $filter)) : '';
240
    }
241
242
    /**
243
    * @return array<int, string>
244
    */
245 40
    final protected function LeftOpRightOpDaftNestedObjectTreeFromArgs(
246
        bool $withRoot,
247
        bool $treeNotPath
248
    ) : array {
249 40
        $leftOp = ($withRoot ? ' >= ' : ' > ');
250 40
        $rightOp = ($withRoot ? ' <= ' : ' < ');
251
252 40
        if ( ! $treeNotPath) {
253 4
            list($leftOp, $rightOp) = [$rightOp, $leftOp];
254
        }
255
256 40
        return [$leftOp, $rightOp];
257
    }
258
259 40
    protected function QueryDaftNestedObjectTreeFromArgs(
260
        bool $recall,
261
        ? int $left,
262
        ? int $right,
263
        ? int $limit,
264
        bool $withRoot,
265
        bool $treeNotPath = self::DEFAULT_BOOL_FETCH_TREE_NOT_PATH
266
    ) : PDOStatement {
267 40
        $queryArgs = [];
268 40
        $filter = [];
269
270 40
        list($leftOp, $rightOp) = $this->LeftOpRightOpDaftNestedObjectTreeFromArgs(
271 40
            $withRoot,
272 40
            $treeNotPath
273
        );
274
275 40
        $escapedLeft = $this->db->escapeIdentifier('intNestedLeft');
276
277
        $maybeArgs = [
278 40
            ($escapedLeft . $leftOp . ' ?') => $left,
279 40
            ($this->db->escapeIdentifier('intNestedRight') . $rightOp . ' ?') => $right,
280 40
            ($this->db->escapeIdentifier('intNestedLevel') . ' <= ?') => $limit,
281
        ];
282
283 40
        foreach (array_filter($maybeArgs, 'is_int') as $filterStr => $queryArgVar) {
284 28
            $queryArgs[] = $queryArgVar;
285 28
            $filter[] = $filterStr;
286
        }
287
288
        $query =
289
            'SELECT ' .
290 40
            $this->SelectingQueryDaftNestedObjectTreeFromArgs($recall) .
291 40
            ' FROM ' .
292 40
            $this->db->escapeIdentifier($this->DaftObjectDatabaseTable()) .
293 40
            $this->FilterQueryDaftNestedObjectTreeFromArgs($filter) .
294 40
            ' ORDER BY ' .
295 40
            $escapedLeft;
296
297 40
        $sth = $this->db->prepare($query);
298
299 40
        $sth->execute($queryArgs);
300
301 40
        return $sth;
302
    }
303
304
    /**
305
    * {@inheritdoc}
306
    *
307
    * @psalm-return array<int, TDbObj>
308
    */
309 28
    protected function RecallDaftNestedObjectTreeFromArgs(
310
        ? int $left,
311
        ? int $right,
312
        ? int $limit,
313
        bool $withRoot,
314
        bool $treeNotPath = true
315
    ) : array {
316 28
        $sth = $this->QueryDaftNestedObjectTreeFromArgs(
317 28
            true,
318 28
            $left,
319 28
            $right,
320 28
            $limit,
321 28
            $withRoot,
322 28
            $treeNotPath
323
        );
324
325
        /**
326
        * @var array<int, DaftNestedObject>
327
        *
328
        * @psalm-var array<int, TDbObj>
329
        */
330 28
        $out = array_filter(
331 28
            array_map(
332
                /**
333
                * @param array<int, scalar|null> $id
334
                */
335
                function (array $id) : ? DaftObject {
336 28
                    return $this->RecallDaftObject($id);
337 28
                },
338 28
                (array) $sth->fetchAll(PDO::FETCH_NUM)
339
            ),
340
            function (? DaftObject $maybe) : bool {
341 28
                return $maybe instanceof DaftNestedObject;
342 28
            }
343
        );
344
345 28
        return $out;
346
    }
347
348 40
    protected function CountDaftNestedObjectTreeFromArgs(
349
        ? int $left,
350
        ? int $right,
351
        ? int $limit,
352
        bool $withRoot,
353
        bool $treeNotPath = true
354
    ) : int {
355 40
        $sth = $this->QueryDaftNestedObjectTreeFromArgs(
356 40
            false,
357 40
            $left,
358 40
            $right,
359 40
            $limit,
360 40
            $withRoot,
361 40
            $treeNotPath
362
        );
363
364 40
        return (int) $sth->fetchColumn();
365
    }
366
}
367