Passed
Push — master ( fe5742...58a66f )
by SignpostMarv
09:54
created

RememberDaftObjectData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

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