MySql::addSearchSql()   A
last analyzed

Complexity

Conditions 5
Paths 2

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 14
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 21
ccs 13
cts 13
cp 1
crap 5
rs 9.4888
1
<?php
2
3
namespace kalanis\nested_tree_nette\Sources\Nette;
4
5
use kalanis\nested_tree\Sources\SourceInterface;
6
use kalanis\nested_tree\Support;
7
use Nette\Database\Explorer;
8
use Nette\Database\Row;
9
use Nette\Database\Table\ActiveRow;
10
use Nette\Database\Table\Selection;
11
12 1
class MySql implements SourceInterface
13
{
14
    use Support\ColumnsTrait;
0 ignored issues
show
introduced by
The trait kalanis\nested_tree\Support\ColumnsTrait requires some properties which are not provided by kalanis\nested_tree_nette\Sources\Nette\MySql: $parentIdColumnName, $positionColumnName, $levelColumnName, $rightColumnName, $leftColumnName, $idColumnName
Loading history...
15
16 1
    public function __construct(
17
        protected readonly Explorer $database,
18
        protected readonly Support\Node $nodeBase,
19
        protected readonly Support\TableSettings $settings,
20
    ) {
21 1
    }
22
23
    /**
24
     * {@inheritdoc}
25
     */
26
    public function selectLastPosition(?int $parentNodeId, ?Support\Conditions $where) : ?int
27
    {
28 1
        $selection = $this->database
29 1
            ->table($this->settings->tableName)
30 1
            ->where([$this->settings->parentIdColumnName => $parentNodeId]);
31 1
        $this->addCustomQuery($selection, $where);
32 1
        $result = $selection
33 1
            ->order($this->settings->positionColumnName . ' DESC')
34 1
            ->fetch();
35
36 1
        return !empty($result) ? max(1, intval($result->{$this->settings->positionColumnName})) : null;
37
    }
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public function selectSimple(Support\Options $options) : array
43
    {
44 1
        $selection = $this->database
45 1
            ->table($this->settings->tableName);
46 1
        $this->addCurrentId($selection, $options);
47 1
        $this->addCustomQuery($selection, $options->where);
48 1
        $result = $selection
49 1
            ->order($this->settings->positionColumnName . ' ASC')
50 1
            ->fetchAll();
51
52 1
        return $result ? $this->fromDbRows($result) : [];
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    public function selectParent(int $nodeId, Support\Options $options) : ?int
59
    {
60 1
        $selection = $this->database
61 1
            ->table($this->settings->tableName)
62 1
            ->where([$this->settings->idColumnName => $nodeId]);
63 1
        $this->addCustomQuery($selection, $options->where, '');
64 1
        $row = $selection->fetch();
65 1
        $parent_id = !empty($row) ? $row->{$this->settings->parentIdColumnName} : null;
66
67 1
        return (empty($parent_id)) ? ($this->settings->rootIsNull ? null : 0) : max(0, intval($parent_id));
68
    }
69
70
    public function selectCount(Support\Options $options) : int
71
    {
72 1
        $sql = 'SELECT ';
73 1
        $sql .= ' ANY_VALUE(parent.' . $this->settings->idColumnName . ') AS p_cid';
74 1
        $sql .= ', ANY_VALUE(parent.' . $this->settings->parentIdColumnName . ') AS p_pid';
75 1
        if (!is_null($options->currentId) || !is_null($options->parentId) || !empty($options->search) || $options->joinChild) {
76 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->idColumnName . ') AS `' . $this->settings->idColumnName . '`';
77 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->parentIdColumnName . ') AS `' . $this->settings->parentIdColumnName . '`';
78 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->leftColumnName . ') AS `' . $this->settings->leftColumnName . '`';
79
        }
80 1
        $sql .= $this->addAdditionalColumns($options);
81 1
        $sql .= ' FROM ' . $this->settings->tableName . ' AS parent';
82
83 1
        if (!is_null($options->currentId) || !is_null($options->parentId) || !empty($options->search) || $options->joinChild) {
84
            // if there is filter or search, there must be inner join to select all of filtered children.
85 1
            $sql .= ' INNER JOIN ' . $this->settings->tableName . ' AS child';
86 1
            $sql .= ' ON child.' . $this->settings->leftColumnName . ' BETWEEN parent.' . $this->settings->leftColumnName . ' AND parent.' . $this->settings->rightColumnName;
87
        }
88
89 1
        $sql .= ' WHERE 1';
90 1
        $params = [];
91 1
        $sql .= $this->addFilterBySql($params, $options);
92 1
        $sql .= $this->addCurrentIdSql($params, $options, 'parent.');
93 1
        $sql .= $this->addParentIdSql($params, $options, 'parent.');
94 1
        $sql .= $this->addSearchSql($params, $options, 'parent.');
95 1
        $sql .= $this->addCustomQuerySql($params, $options->where);
96 1
        $sql .= $this->addSortingSql($params, $options);
97
98
        // get 'total' count.
99 1
        $result = $this->database->fetchAll($sql, ...$params);
100
101
        // "a bit" hardcore - get all lines and then count them
102 1
        return $result ? count($result) : 0;
103
    }
104
105
    public function selectLimited(Support\Options $options) : array
106
    {
107 1
        $sql = 'SELECT';
108 1
        $sql .= ' ANY_VALUE(parent.' . $this->settings->idColumnName . ') AS p_pid';
109 1
        $sql .= ', ANY_VALUE(parent.' . $this->settings->parentIdColumnName . ') AS p_cid';
110 1
        $sql .= ', ANY_VALUE(parent.' . $this->settings->leftColumnName . ') AS p_plt';
111 1
        if (!is_null($options->currentId) || !is_null($options->parentId) || !empty($options->search) || $options->joinChild) {
112 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->idColumnName . ') AS `' . $this->settings->idColumnName . '`';
113 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->parentIdColumnName . ') AS `' . $this->settings->parentIdColumnName . '`';
114 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->leftColumnName . ') AS `' . $this->settings->leftColumnName . '`';
115 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->rightColumnName . ') AS `' . $this->settings->rightColumnName . '`';
116 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->levelColumnName . ') AS `' . $this->settings->levelColumnName . '`';
117 1
            $sql .= ', ANY_VALUE(child.' . $this->settings->positionColumnName . ') AS `' . $this->settings->positionColumnName . '`';
118
        }
119 1
        $sql .= $this->addAdditionalColumns($options);
120 1
        $sql .= ' FROM ' . $this->settings->tableName . ' AS parent';
121
122 1
        if (!is_null($options->currentId) || !is_null($options->parentId) || !empty($options->search) || $options->joinChild) {
123
            // if there is filter or search, there must be inner join to select all of filtered children.
124 1
            $sql .= ' INNER JOIN ' . $this->settings->tableName . ' AS child';
125 1
            $sql .= ' ON child.' . $this->settings->leftColumnName . ' BETWEEN parent.' . $this->settings->leftColumnName . ' AND parent.' . $this->settings->rightColumnName;
126
        }
127
128 1
        $sql .= ' WHERE 1';
129 1
        $params = [];
130 1
        $sql .= $this->addFilterBySql($params, $options);
131 1
        $sql .= $this->addCurrentIdSql($params, $options, 'parent.');
132 1
        $sql .= $this->addParentIdSql($params, $options, 'parent.');
133 1
        $sql .= $this->addSearchSql($params, $options, 'parent.');
134 1
        $sql .= $this->addCustomQuerySql($params, $options->where);
135 1
        $sql .= $this->addSortingSql($params, $options);
136
137
        // re-create query and prepare. second step is for set limit and fetch all items.
138 1
        if (!$options->unlimited) {
139 1
            if (empty($options->offset)) {
140 1
                $options->offset = 0;
141
            }
142 1
            if (empty($options->limit) || (10000 < $options->limit)) {
143 1
                $options->limit = 20;
144
            }
145
146 1
            $sql .= ' LIMIT ' . $options->offset . ', ' . $options->limit;
147
        }
148
149 1
        $result = $this->database->fetchAll($sql, ...$params);
150
151 1
        return $result ? $this->fromDbRows($result) : [];
152
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157
    public function selectWithParents(Support\Options $options) : array
158
    {
159 1
        $params = [];
160 1
        $sql = 'SELECT';
161 1
        $sql .= ' ANY_VALUE(parent.' . $this->settings->idColumnName . ') AS `' . $this->settings->idColumnName . '`';
162 1
        $sql .= ', ANY_VALUE(parent.' . $this->settings->parentIdColumnName . ') AS `' . $this->settings->parentIdColumnName . '`';
163 1
        $sql .= ', ANY_VALUE(parent.' . $this->settings->leftColumnName . ') AS `' . $this->settings->leftColumnName . '`';
164 1
        $sql .= ', ANY_VALUE(parent.' . $this->settings->rightColumnName . ') AS `' . $this->settings->rightColumnName . '`';
165 1
        $sql .= ', ANY_VALUE(parent.' . $this->settings->levelColumnName . ') AS `' . $this->settings->levelColumnName . '`';
166 1
        $sql .= ', ANY_VALUE(parent.' . $this->settings->positionColumnName . ') AS `' . $this->settings->positionColumnName . '`';
167 1
        $sql .= $this->addAdditionalColumns($options);
168 1
        $sql .= ' FROM ' . $this->settings->tableName . ' AS node,';
169 1
        $sql .= ' ' . $this->settings->tableName . ' AS parent';
170 1
        $sql .= ' WHERE';
171 1
        $sql .= ' (node.' . $this->settings->leftColumnName . ' BETWEEN parent.' . $this->settings->leftColumnName . ' AND parent.' . $this->settings->rightColumnName . ')';
172 1
        $sql .= $this->addCurrentIdSql($params, $options, 'node.');
173 1
        $sql .= $this->addSearchSql($params, $options, 'node.');
174 1
        $sql .= $this->addCustomQuerySql($params, $options->where);
175 1
        $sql .= ' GROUP BY parent.`' . $this->settings->idColumnName . '`';
176 1
        $sql .= ' ORDER BY parent.`' . $this->settings->leftColumnName . '`';
177
178 1
        $result = $this->database->fetchAll($sql, ...$params);
179
180 1
        if (empty($result)) {
181 1
            return [];
182
        }
183 1
        if ($options->skipCurrent) {
184 1
            unset($result[count($result)-1]);
185
        }
186
187 1
        return $this->fromDbRows($result);
188
    }
189
190
    public function add(Support\Node $node, ?Support\Conditions $where = null) : Support\Node
191
    {
192 1
        $pairs = [];
193 1
        foreach ((array) $node as $column => $value) {
194 1
            if (!is_numeric($column) && !$this->isColumnNameFromBasic($column)) {
195 1
                $translateColumn = $this->translateColumn($this->settings, $column);
196 1
                $pairs[$translateColumn] = $value;
197
            }
198
        }
199
200 1
        $row = $this->database
201 1
            ->table($this->settings->tableName)
202 1
            ->insert($pairs);
203 1
        $node = !empty($row) && is_object($row) && (is_a($row, ActiveRow::class) || is_a($row, Row::class)) ? $this->fillDataFromRow($row) : null;
204
205 1
        if (is_null($node)) {
206
            // @codeCoverageIgnoreStart
207
            // when this happens it is problem with DB, not with library
208
            throw new \RuntimeException('Node not found in database');
209
        }
210
        // @codeCoverageIgnoreEnd
211
212 1
        return $node;
213
    }
214
215
    public function updateData(Support\Node $node, ?Support\Conditions $where = null) : bool
216
    {
217 1
        $pairs = [];
218 1
        foreach ((array) $node as $column => $value) {
219
            if (
220 1
                !is_numeric($column)
221 1
                && !$this->isColumnNameFromBasic($column)
222 1
                && !$this->isColumnNameFromTree($column)
223 1
                && !is_null($value)
224
            ) {
225 1
                $translateColumn = $this->translateColumn($this->settings, $column);
226 1
                $pairs[$translateColumn] = $value;
227
            }
228
        }
229
230 1
        $count = $this->database
231 1
            ->table($this->settings->tableName)
232 1
            ->where([$this->settings->idColumnName => $node->id])
233 1
            ->update($pairs);
234
235 1
        return !empty($count);
236
    }
237
238
    /**
239
     * {@inheritdoc}
240
     */
241
    public function updateNodeParent(int $nodeId, ?int $parentId, int $position, ?Support\Conditions $where) : bool
242
    {
243 1
        $selection = $this->database
244 1
            ->table($this->settings->tableName)
245 1
            ->where([$this->settings->idColumnName => $nodeId]);
246 1
        $this->addCustomQuery($selection, $where, '');
247
248 1
        $counter = $selection->update([
249 1
            $this->settings->parentIdColumnName => $parentId,
250 1
            $this->settings->positionColumnName => $position,
251
        ]);
252
253 1
        return !empty($counter);
254
    }
255
256
    /**
257
     * {@inheritdoc}
258
     */
259
    public function updateChildrenParent(int $nodeId, ?int $parentId, ?Support\Conditions $where) : bool
260
    {
261 1
        $selection = $this->database
262 1
            ->table($this->settings->tableName)
263 1
            ->where([$this->settings->parentIdColumnName => $nodeId]);
264 1
        $this->addCustomQuery($selection, $where, '');
265
266 1
        $counter = $selection->update([
267 1
            $this->settings->parentIdColumnName => $parentId,
268
        ]);
269
270 1
        return !empty($counter);
271
    }
272
273
    public function updateLeftRightPos(Support\Node $row, ?Support\Conditions $where) : bool
274
    {
275 1
        $selection = $this->database
276 1
            ->table($this->settings->tableName)
277 1
            ->where([$this->settings->idColumnName => $row->id]);
278 1
        $this->addCustomQuery($selection, $where, '');
279
280 1
        $counter = $selection->update([
281 1
            $this->settings->levelColumnName => $row->level,
282 1
            $this->settings->leftColumnName => $row->left,
283 1
            $this->settings->rightColumnName => $row->right,
284 1
            $this->settings->positionColumnName => $row->position,
285
        ]);
286
287 1
        return !empty($counter);
288
    }
289
290
    /**
291
     * {@inheritdoc}
292
     */
293
    public function makeHole(?int $parentId, int $position, bool $moveUp, ?Support\Conditions $where = null) : bool
294
    {
295 1
        $direction = $moveUp ? '-' : '+';
296 1
        $compare = $moveUp ? '<=' : '>=';
297 1
        $sql = 'UPDATE ' . $this->settings->tableName;
298 1
        $sql .= ' SET ' . $this->settings->positionColumnName . ' = ' . $this->settings->positionColumnName . ' ' . $direction . ' 1';
299 1
        $sql .= ' WHERE ' . $this->settings->parentIdColumnName . ' = ?';
300 1
        $sql .= ' AND ' . $this->settings->positionColumnName . ' ' . $compare . ' ?';
301 1
        $params = [
302 1
            $parentId,
303 1
            $position,
304
        ];
305
306 1
        $sql .= $this->addCustomQuerySql($params, $where, '');
307
308 1
        $this->database->fetch($sql, ...$params);
309
310 1
        return true;
311
    }
312
313
    /**
314
     * {@inheritdoc}
315
     */
316
    public function deleteSolo(int $nodeId, ?Support\Conditions $where) : bool
317
    {
318 1
        $selection = $this->database
319 1
            ->table($this->settings->tableName)
320 1
            ->where([$this->settings->idColumnName => $nodeId]);
321 1
        $this->addCustomQuery($selection, $where, '');
322 1
        $counter = $selection->delete();
323
324 1
        return !empty($counter);
325
    }
326
327
    public function deleteWithChildren(Support\Node $row, ?Support\Conditions $where) : bool
328
    {
329 1
        $selection = $this->database
330 1
            ->table($this->settings->tableName)
331 1
            ->where([$this->settings->idColumnName => $row->id]);
332 1
        $this->addCustomQuery($selection, $where, '');
333 1
        $counter = $selection->delete();
334
335 1
        return !empty($counter);
336
    }
337
338
    /**
339
     * @param array<Row|ActiveRow> $rows
340
     * @return array<int<0, max>, Support\Node>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<int<0, max>, Support\Node> at position 2 could not be parsed: Expected '>' at position 2, but found 'int'.
Loading history...
341
     */
342
    protected function fromDbRows(array $rows) : array
343
    {
344 1
        $result = [];
345 1
        foreach ($rows as &$row) {
346 1
            $data = $this->fillDataFromRow($row);
347 1
            $result[$data->id] = $data;
348
        }
349
350 1
        return $result;
351
    }
352
353
    protected function fillDataFromRow(Row|ActiveRow $row) : Support\Node
354
    {
355 1
        $data = clone $this->nodeBase;
356 1
        foreach ($row as $k => $v) {
357 1
            if ($this->settings->idColumnName === $k) {
358 1
                $data->id = max(0, intval($v));
359 1
            } elseif ($this->settings->parentIdColumnName === $k) {
360 1
                $data->parentId = is_null($v) && $this->settings->rootIsNull ? null : max(0, intval($v));
361 1
            } elseif ($this->settings->levelColumnName === $k) {
362 1
                $data->level = max(0, intval($v));
363 1
            } elseif ($this->settings->leftColumnName === $k) {
364 1
                $data->left = max(0, intval($v));
365 1
            } elseif ($this->settings->rightColumnName === $k) {
366 1
                $data->right = max(0, intval($v));
367 1
            } elseif ($this->settings->positionColumnName === $k) {
368 1
                $data->position = max(0, intval($v));
369
            } else {
370 1
                $data->{$k} = strval($v);
371
            }
372
        }
373
374 1
        return $data;
375
    }
376
377
    protected function bindToQuery(string $string) : string
378
    {
379 1
        return strval(preg_replace('#(:[^\s]+)#', '?', $string));
380
    }
381
382
    protected function replaceColumns(string $query, string $byWhat = '') : string
383
    {
384 1
        foreach (['`parent`.', '`child`.', 'parent.', 'child.'] as $toReplace) {
385 1
            $query = str_replace($toReplace, $byWhat, $query);
386
        }
387
388 1
        return $query;
389
    }
390
391
    protected function addAdditionalColumns(Support\Options $options, ?string $replaceName = null) : string
392
    {
393 1
        $sql = '';
394 1
        if (!empty($options->additionalColumns)) {
395 1
            foreach ($options->additionalColumns as $column) {
396 1
                $sql .= ', ' . (!is_null($replaceName) ? $this->replaceColumns($column, $replaceName) : $column);
397
            }
398
        }
399
400 1
        return $sql;
401
    }
402
403
    /**
404
     * @param array<mixed> $params
405
     * @param Support\Options $options
406
     * @return string
407
     */
408
    protected function addFilterBySql(array &$params, Support\Options $options) : string
409
    {
410 1
        $sql = '';
411 1
        if (!empty($options->filterIdBy)) {
412
            // Nette and other serious frameworks can bind directly, just kick out non-usable params
413 1
            $entries = $this->filteredEntries($options->filterIdBy);
414 1
            $positions = implode(',', array_fill(1, count($entries), '?'));
415 1
            $sql .= ' AND parent.' . $this->settings->idColumnName . ' IN (' . $positions . ')';
416 1
            $params = array_merge($params, array_values($entries));
417
        }
418
419 1
        return $sql;
420
    }
421
422
    /**
423
     * @param Selection<ActiveRow> $selection
424
     * @param Support\Options $options
425
     * @param string $dbPrefix
426
     * @return void
427
     */
428
    protected function addCurrentId(Selection $selection, Support\Options $options, string $dbPrefix = '') : void
429
    {
430 1
        if (!is_null($options->currentId)) {
431 1
            $selection->where([$dbPrefix . $this->settings->idColumnName => $options->currentId]);
432
        }
433 1
    }
434
435
    /**
436
     * @param array<mixed> $params
437
     * @param Support\Options $options
438
     * @param string $dbPrefix
439
     * @return string
440
     */
441
    protected function addCurrentIdSql(array &$params, Support\Options $options, string $dbPrefix = '') : string
442
    {
443 1
        $sql = '';
444 1
        if (!is_null($options->currentId)) {
445 1
            $sql .= ' AND ' . $dbPrefix . $this->settings->idColumnName . ' = ?';
446 1
            $params[] = $options->currentId;
447
        }
448
449 1
        return $sql;
450
    }
451
452
    /**
453
     * @param array<mixed> $params
454
     * @param Support\Options $options
455
     * @param string $dbPrefix
456
     * @return string
457
     */
458
    protected function addParentIdSql(array &$params, Support\Options $options, string $dbPrefix = '') : string
459
    {
460 1
        $sql = '';
461 1
        if (!is_null($options->parentId)) {
462 1
            $sql .= ' AND ' . $dbPrefix . $this->settings->parentIdColumnName . ' = ?';
463 1
            $params[] = $options->parentId;
464
        }
465
466 1
        return $sql;
467
    }
468
469
    /**
470
     * @param array<mixed> $params
471
     * @param Support\Options $options
472
     * @param string $dbPrefix
473
     * @return string
474
     */
475
    protected function addSearchSql(array &$params, Support\Options $options, string $dbPrefix = '') : string
476
    {
477 1
        $sql = '';
478
        if (
479 1
            !empty($options->search->columns)
480 1
            && !empty($options->search->value)
481
        ) {
482 1
            $sql .= ' AND (';
483 1
            $array_keys = array_keys($options->search->columns);
484 1
            $last_array_key = array_pop($array_keys);
485 1
            foreach ($options->search->columns as $key => $column) {
486 1
                $sql .= $dbPrefix . $column . ' LIKE ?';
487 1
                $params[] = '%' . $options->search->value . '%';
488 1
                if ($key !== $last_array_key) {
489 1
                    $sql .= ' OR ';
490
                }
491
            }
492 1
            $sql .= ')';
493
        }
494
495 1
        return $sql;
496
    }
497
498
    /**
499
     * @param Selection<ActiveRow> $selection
500
     * @param Support\Conditions|null $where
501
     * @param string|null $replaceName
502
     * @return void
503
     */
504
    protected function addCustomQuery(Selection $selection, ?Support\Conditions $where, ?string $replaceName = null) : void
505
    {
506 1
        if (!empty($where->query)) {
507 1
            $name = (!is_null($replaceName) ? $this->replaceColumns($where->query, $replaceName) : $where->query);
508 1
            $selection->where($this->bindToQuery($name), ...array_values($where->bindValues ?? []));
509
        }
510 1
    }
511
512
    /**
513
     * @param array<mixed> $params
514
     * @param Support\Conditions|null $where
515
     * @param string|null $replaceName
516
     * @return string
517
     */
518
    protected function addCustomQuerySql(array &$params, ?Support\Conditions $where, ?string $replaceName = null) : string
519
    {
520 1
        $sql = '';
521 1
        if (!empty($where->query)) {
522 1
            $sql .= ' AND ' . (!is_null($replaceName) ? $this->replaceColumns($where->query, $replaceName) : $where->query);
523 1
            $params = array_merge($params, array_values($where->bindValues ?? []));
524
        }
525
526 1
        return $sql;
527
    }
528
529
    /**
530
     * @param array<mixed> $params
531
     * @param Support\Options $options
532
     * @return string
533
     */
534
    protected function addSortingSql(array &$params, Support\Options $options) : string
535
    {
536 1
        $sql = '';
537 1
        if (!$options->noSortOrder) {
538 1
            if (!is_null($options->currentId) || !is_null($options->parentId) || !empty($options->search) || $options->joinChild) {
539 1
                $sql .= ' GROUP BY child.' . $this->settings->idColumnName;
540 1
                $order_by = 'child.' . $this->settings->leftColumnName . ' ASC';
541 1
            } elseif (!empty($options->filterIdBy)) {
542 1
                $entries = $this->filteredEntries($options->filterIdBy);
543 1
                $nodeIdIn = implode(',', array_fill(1, count($entries), '?'));
544 1
                $order_by = 'FIELD(' . $this->settings->idColumnName . ',' . $nodeIdIn . ')';
545 1
                $params = array_merge($params, array_values($entries));
546
            } else {
547 1
                $order_by = 'parent.' . $this->settings->leftColumnName . ' ASC';
548
            }
549 1
            $sql .= ' ORDER BY ' . $order_by;
550 1
        } elseif ($options->joinChild) {
551 1
            $sql .= ' GROUP BY ' . $this->settings->idColumnName;
552
        }
553
554 1
        return $sql;
555
    }
556
557
    /**
558
     * @param array<mixed> $entries
559
     * @return array<string|int|float|null>
560
     */
561
    protected function filteredEntries(array $entries) : array
562
    {
563 1
        return array_filter($entries, function ($entry) : bool {
564 1
            return is_null($entry) || is_numeric($entry) || is_string($entry);
565 1
        });
566
    }
567
}
568