Passed
Push — master ( 41d371...1d5b17 )
by SignpostMarv
06:22
created

QueryDaftNestedObjectTreeFromArgs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 43
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 2

Importance

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