Completed
Push — develop ( 4f051c...c7250c )
by Bartko
07:21 queued 05:04
created

Doctrine2DBAL::getRoots()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 14
cts 14
cp 1
rs 9.0856
c 0
b 0
f 0
cc 3
eloc 13
nc 2
nop 1
crap 3
1
<?php
2
namespace StefanoTree\NestedSet\Adapter;
3
4
use Doctrine\DBAL\Connection as DbConnection;
5
use Doctrine\DBAL\Query\QueryBuilder;
6
use StefanoTree\NestedSet\NodeInfo;
7
use StefanoTree\NestedSet\Options;
8
9
class Doctrine2DBAL
10
    implements AdapterInterface
0 ignored issues
show
Coding Style introduced by
The implements keyword must be on the same line as the class name
Loading history...
11
{
12
    private $options;
13
14
    private $connection;
15
16
    private $defaultDbSelect;
17
18
    /**
19
     * @param Options $options
20
     * @param DbConnection $connection
21
     */
22 49
    public function __construct(Options $options, DbConnection $connection)
23
    {
24 49
        $this->options = $options;
25 49
        $this->connection = $connection;
26 49
    }
27
28
    /**
29
     * @return Options
30
     */
31 46
    private function getOptions()
32
    {
33 46
        return $this->options;
34
    }
35
36
    /**
37
     * @return DbConnection
38
     */
39 47
    private function getConnection()
40
    {
41 47
        return $this->connection;
42
    }
43
44
45
    /**
46
     * Data cannot contain keys like idColumnName, levelColumnName, ...
47
     *
48
     * @param array $data
49
     * @return array
50
     */
51 3
    private function cleanData(array $data)
52
    {
53 3
        $options = $this->getOptions();
54
55
        $disallowedDataKeys = array(
56 3
            $options->getIdColumnName(),
57 3
            $options->getLeftColumnName(),
58 3
            $options->getRightColumnName(),
59 3
            $options->getLevelColumnName(),
60 3
            $options->getParentIdColumnName(),
61 3
            $options->getScopeColumnName(),
62 3
        );
63
64 3
        return array_diff_key($data, array_flip($disallowedDataKeys));
65
    }
66
67
    /**
68
     * Return base db select without any join, etc.
69
     * @return QueryBuilder
70
     */
71 24
    public function getBlankDbSelect()
72
    {
73 24
        $queryBuilder = $this->getConnection()
74 24
            ->createQueryBuilder();
75
76 24
        $queryBuilder->select('*')
77 24
            ->from($this->getOptions()->getTableName(), null);
78
79 24
        return $queryBuilder;
80
    }
81
82
    /**
83
     * @param QueryBuilder $dbSelect
84
     * @return void
85
     */
86 1
    public function setDefaultDbSelect(QueryBuilder $dbSelect)
87
    {
88 1
        $this->defaultDbSelect = $dbSelect;
89 1
    }
90
91
    /**
92
     * Return clone of default db select
93
     * @return QueryBuilder
94
     */
95 14
    public function getDefaultDbSelect()
96
    {
97 14
        if (null === $this->defaultDbSelect) {
98 13
            $this->defaultDbSelect = $this->getBlankDbSelect();
99 13
        }
100
101 14
        $dbSelect = clone $this->defaultDbSelect;
102
103 14
        return $dbSelect;
104
    }
105
106 1
    public function lockTree()
107
    {
108 1
        $options = $this->getOptions();
109
110 1
        $connection = $this->getConnection();
111
112 1
        $sql = $this->getBlankDbSelect();
113 1
        $sql->select($options->getIdColumnName() . ' AS i');
114
115 1
        $sql = $sql->getSQL() . ' FOR UPDATE';
116
117 1
        $connection->executeQuery($sql);
118 1
    }
119
120 1
    public function beginTransaction()
121
    {
122 1
        $this->getConnection()
123 1
            ->beginTransaction();
124 1
    }
125
126 1
    public function commitTransaction()
127
    {
128 1
        $this->getConnection()
129 1
            ->commit();
130 1
    }
131
132 1
    public function rollbackTransaction()
133
    {
134 1
        $this->getConnection()
135 1
            ->rollBack();
136 1
    }
137
138 3
    public function update($nodeId, array $data)
139
    {
140 3
        $options = $this->getOptions();
141
142 3
        $connection = $this->getConnection();
143
144 3
        $data = $this->cleanData($data);
145
146 3
        $sql = $connection->createQueryBuilder();
147
148 3
        $sql->update($options->getTableName(), null)
149 3
            ->where($options->getIdColumnName() . ' = :' . $options->getIdColumnName());
150
151 3
        foreach ($data as $key => $value) {
152 3
            $sql->set($connection->quoteIdentifier($key), ':' . $key);
153 3
        }
154
155 3
        $data[$options->getIdColumnName()] = $nodeId;
156
157 3
        $connection->executeUpdate($sql, $data);
158 3
    }
159
160 3
    public function insert(NodeInfo $nodeInfo, array $data)
161
    {
162 3
        $options = $this->getOptions();
163
164 3
        $connection = $this->getConnection();
165
166 3
        $data[$options->getParentIdColumnName()] = $nodeInfo->getParentId();
167 3
        $data[$options->getLevelColumnName()]    = $nodeInfo->getLevel();
168 3
        $data[$options->getLeftColumnName()]     = $nodeInfo->getLeft();
169 3
        $data[$options->getRightColumnName()]    = $nodeInfo->getRight();
170
171 3
        if ($options->getScopeColumnName()) {
172 1
            $data[$options->getScopeColumnName()] = $nodeInfo->getScope();
173 1
        }
174
175 3
        $connection->insert($options->getTableName(), $data);
176
177 3
        return $connection->lastInsertId($options->getSequenceName());
178
    }
179
180 2
    public function delete($nodeId)
181
    {
182 2
        $options = $this->getOptions();
183
184 2
        $connection = $this->getConnection();
185
186 2
        $sql = $connection->createQueryBuilder();
187 2
        $sql->delete($options->getTableName())
188 2
            ->where($options->getIdColumnName() . ' = :id');
189
190
        $params = array(
191 2
            ':id' => $nodeId,
192 2
        );
193
194 2
        $connection->executeQuery($sql, $params);
195 2
    }
196
197 2
    public function moveLeftIndexes($fromIndex, $shift, $scope = null)
198
    {
199 2
        $options = $this->getOptions();
200
201 2
        if (0 == $shift) {
202
            return;
203
        }
204
205 2
        $connection = $this->getConnection();
206
207 2
        $sql = $connection->createQueryBuilder();
208 2
        $sql->update($options->getTableName())
209 2
            ->set($options->getLeftColumnName(), $options->getLeftColumnName() . ' + :shift')
210 2
            ->where($options->getLeftColumnName() . ' > :fromIndex');
211
212
        $params = array(
213 2
            ':shift' => $shift,
214 2
            ':fromIndex' => $fromIndex,
215 2
        );
216
217 2
        if ($options->getScopeColumnName()) {
218 1
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
219 1
            $params[':scope'] = $scope;
220 1
        }
221
222 2
        $connection->executeUpdate($sql, $params);
223 2
    }
224
225 2
    public function moveRightIndexes($fromIndex, $shift, $scope = null)
226
    {
227 2
        $options = $this->getOptions();
228
229 2
        if (0 == $shift) {
230
            return;
231
        }
232
233 2
        $connection = $this->getConnection();
234
235 2
        $sql = $connection->createQueryBuilder();
236 2
        $sql->update($options->getTableName())
237 2
            ->set($options->getRightColumnName(), $options->getRightColumnName() . ' + :shift')
238 2
            ->where($options->getRightColumnName() . ' > :fromIndex');
239
240
        $params = array(
241 2
            ':shift' => $shift,
242 2
            ':fromIndex' => $fromIndex,
243 2
        );
244
245 2
        if ($options->getScopeColumnName()) {
246 1
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
247 1
            $params[':scope'] = $scope;
248 1
        }
249
250 2
        $connection->executeUpdate($sql, $params);
251 2
    }
252
253 1
    public function updateParentId($nodeId, $newParentId)
254
    {
255 1
        $options = $this->getOptions();
256
257 1
        $connection = $this->getConnection();
258
259 1
        $sql = $connection->createQueryBuilder();
260 1
        $sql->update($options->getTableName())
261 1
            ->set($options->getParentIdColumnName(), ':parentId')
262 1
            ->where($options->getIdColumnName() . ' = :nodeId');
263
264
        $params = array(
265 1
            ':parentId' => $newParentId,
266 1
            ':nodeId' => $nodeId,
267 1
        );
268
269 1
        $connection->executeUpdate($sql, $params);
270 1
    }
271
272 2
    public function updateLevels($leftIndexFrom, $rightIndexTo, $shift, $scope = null)
273
    {
274 2
        $options = $this->getOptions();
275
276 2
        if (0 == $shift) {
277
            return;
278
        }
279
280 2
        $connection = $this->getConnection();
281
282 2
        $sql = $connection->createQueryBuilder();
283 2
        $sql->update($options->getTableName())
284 2
            ->set($options->getLevelColumnName(), $options->getLevelColumnName() . ' + :shift')
285 2
            ->where($options->getLeftColumnName() . ' >= :leftFrom'
286 2
                . ' AND ' . $options->getRightColumnName() . ' <= :rightTo');
287
288
        $params = array(
289 2
            ':shift' => $shift,
290 2
            ':leftFrom' => $leftIndexFrom,
291 2
            ':rightTo' => $rightIndexTo,
292 2
        );
293
294 2
        if ($options->getScopeColumnName()) {
295 1
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
296 1
            $params[':scope'] = $scope;
297 1
        }
298
299 2
        $connection->executeUpdate($sql, $params);
300 2
    }
301
302 2
    public function moveBranch($leftIndexFrom, $rightIndexTo, $shift, $scope = null)
303
    {
304 2
        if (0 == $shift) {
305
            return;
306
        }
307
308 2
        $options = $this->getOptions();
309
310 2
        $connection = $this->getConnection();
311
312 2
        $sql = $connection->createQueryBuilder();
313 2
        $sql->update($options->getTableName())
314 2
            ->set($options->getLeftColumnName(), $options->getLeftColumnName() . ' + :shift')
315 2
            ->set($options->getRightColumnName(), $options->getRightColumnName() . ' + :shift')
316 2
            ->where($options->getLeftColumnName() . ' >= :leftFrom'
317 2
                . ' AND ' . $options->getRightColumnName() . ' <= :rightTo');
318
319
        $params = array(
320 2
            ':shift' => $shift,
321 2
            ':leftFrom' => $leftIndexFrom,
322 2
            ':rightTo' => $rightIndexTo,
323 2
        );
324
325 2
        if ($options->getScopeColumnName()) {
326 1
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
327 1
            $params[':scope'] = $scope;
328 1
        }
329
330 2
        $connection->executeUpdate($sql, $params);
331 2
    }
332
333 4
    public function getRoots($scope = null)
334
    {
335 4
        $options = $this->getOptions();
336
337 4
        $connection = $this->getConnection();
338
339 4
        $sql = $this->getBlankDbSelect();
340 4
        $sql->where($options->getParentIdColumnName() . ' IS NULL');
341 4
        $sql->orderBy($options->getIdColumnName());
342
343 4
        $params = array();
344
345 4
        if (null != $scope && $options->getScopeColumnName()) {
346 1
            $sql->where($options->getScopeColumnName() . ' = :scope');
347 1
            $params[':scope'] = $scope;
348 1
        }
349
350 4
        $stmt = $connection->executeQuery($sql, $params);
351
352 4
        $node = $stmt->fetchAll();
353
354 4
        return $node;
355
    }
356
357 2
    public function getRoot($scope = null)
358
    {
359 2
        $roots = $this->getRoots($scope);
360 2
        return ($roots) ?  $roots[0] : array();
361
    }
362
363 2
    public function getNode($nodeId)
364
    {
365 2
        $options = $this->getOptions();
366
367 2
        $nodeId = (int) $nodeId;
368
369 2
        $connection = $this->getConnection();
370
371
372 2
        $sql = $this->getDefaultDbSelect();
373 2
        $sql->where($options->getIdColumnName() . ' = :' . $options->getIdColumnName());
374
375
        $params = array(
376 2
            $options->getIdColumnName() => $nodeId,
377 2
        );
378
379 2
        $stmt = $connection->executeQuery($sql, $params);
380
381 2
        $node = $stmt->fetch();
382
383 2
        return is_array($node) ? $node : null;
384
    }
385
386
    /**
387
     * @param array $data
388
     * @return NodeInfo
389
     */
390 14
    private function _buildNodeInfoObject(array $data)
391
    {
392 14
        $options = $this->getOptions();
393
394 14
        $id        = $data[$options->getIdColumnName()];
395 14
        $parentId  = $data[$options->getParentIdColumnName()];
396 14
        $level     = $data[$options->getLevelColumnName()];
397 14
        $left      = $data[$options->getLeftColumnName()];
398 14
        $right     = $data[$options->getRightColumnName()];
399
400 14
        if (isset($data[$options->getScopeColumnName()])) {
401 3
            $scope = $data[$options->getScopeColumnName()];
402 3
        } else {
403 11
            $scope = null;
404
        }
405
406 14
        return new NodeInfo($id, $parentId, $level, $left, $right, $scope);
407
    }
408
409 15
    public function getNodeInfo($nodeId)
410
    {
411 15
        $options = $this->getOptions();
412
413 15
        $nodeId = (int) $nodeId;
414
415 15
        $connection = $this->getConnection();
416
417
418 15
        $sql = $this->getBlankDbSelect();
419 15
        $sql->where($options->getIdColumnName() . ' = :' . $options->getIdColumnName());
420
421
        $params = array(
422 15
            $options->getIdColumnName() => $nodeId,
423 15
        );
424
425 15
        $stmt = $connection->executeQuery($sql, $params);
426
427 15
        $node = $stmt->fetch();
428
429 15
        $data = is_array($node) ? $node : null;
430
431 15
        $result = ($data) ? $this->_buildNodeInfoObject($data) : null;
432
433 15
        return $result;
434
    }
435
436 3
    public function getChildrenNodeInfo($parentNodeId)
437
    {
438 3
        $connection = $this->getConnection();
439 3
        $options = $this->getOptions();
440
441 3
        $queryBuilder = $connection->createQueryBuilder();
442
443
        $columns = array(
444 3
            $options->getIdColumnName(),
445 3
            $options->getLeftColumnName(),
446 3
            $options->getRightColumnName(),
447 3
            $options->getParentIdColumnName(),
448 3
            $options->getLevelColumnName(),
449 3
        );
450
451 3
        $sql = $queryBuilder->select($columns)
452 3
            ->from($options->getTableName())
453 3
            ->where($options->getParentIdColumnName() . ' = :parentId')
454 3
            ->orderBy($options->getLeftColumnName(), 'ASC');
455
456
        $params = array(
457 3
            'parentId' => $parentNodeId,
458 3
        );
459
460 3
        $stmt = $connection->executeQuery($sql, $params);
461
462 3
        $data = $stmt->fetchAll();
463
464 3
        $result = array();
465
466 3
        foreach ($data as $nodeData) {
467 2
            $result[] = $this->_buildNodeInfoObject($nodeData);
468 3
        }
469
470 3
        return $result;
471
    }
472
473 2
    public function updateNodeMetadata(NodeInfo $nodeInfo)
474
    {
475 2
        $options = $this->getOptions();
476
477 2
        $connection = $this->getConnection();
478
479 2
        $sql = $connection->createQueryBuilder();
480 2
        $sql->update($options->getTableName())
481 2
            ->set($options->getRightColumnName(), $nodeInfo->getRight())
482 2
            ->set($options->getLeftColumnName(), $nodeInfo->getLeft())
483 2
            ->set($options->getLevelColumnName(), $nodeInfo->getLevel())
484 2
            ->where($options->getIdColumnName() . ' = :nodeId');
485
486
        $params = array(
487 2
            ':nodeId' => $nodeInfo->getId(),
488 2
        );
489
490 2
        $connection->executeUpdate($sql, $params);
491 2
    }
492
493 5
    public function getPath($nodeId, $startLevel = 0, $excludeLastNode = false)
494
    {
495 5
        $options = $this->getOptions();
496
497 5
        $startLevel = (int) $startLevel;
498
499
        // node does not exist
500 5
        $nodeInfo = $this->getNodeInfo($nodeId);
501 5
        if (!$nodeInfo) {
502 1
            return array();
503
        }
504
505 4
        $connection = $this->getConnection();
506
507 4
        $sql = $this->getDefaultDbSelect();
508 4
        $params = array();
509
510 4
        if ($options->getScopeColumnName()) {
511 1
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
512 1
            $params['scope'] = $nodeInfo->getScope();
513 1
        }
514
515 4
        $sql->andWhere($options->getLeftColumnName() . ' <= :leftIndex')
516 4
            ->andWhere($options->getRightColumnName() . ' >= :rightIndex')
517 4
            ->orderBy($options->getLeftColumnName(), 'ASC');
518
519 4
        $params['leftIndex'] = $nodeInfo->getLeft();
520 4
        $params['rightIndex'] = $nodeInfo->getRight();
521
522 4
        if (0 < $startLevel) {
523 1
            $sql->andWhere($options->getLevelColumnName() . ' >= :startLevel');
524
525 1
            $params['startLevel'] = $startLevel;
526 1
        }
527
528 4
        if (true == $excludeLastNode) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
529 1
            $sql->andWhere($options->getLevelColumnName() . ' < :level');
530
531 1
            $params['level'] = $nodeInfo->getLevel();
532 1
        }
533
534 4
        $stmt = $connection->executeQuery($sql, $params);
535
536 4
        $result = $stmt->fetchAll();
537
538 4
        return (is_array($result)) ? $result : array();
539
    }
540
541 7
    public function getDescendants($nodeId = 1, $startLevel = 0, $levels = null, $excludeBranch = null)
542
    {
543 7
        $options = $this->getOptions();
544
545 7
        if (!$nodeInfo = $this->getNodeInfo($nodeId)) {
546 1
            return array();
547
        }
548
549 6
        $connection = $this->getConnection();
550 6
        $sql = $this->getDefaultDbSelect();
551 6
        $sql->orderBy($options->getLeftColumnName(), 'ASC');
552
553 6
        $params = array();
554
555 6
        if ($options->getScopeColumnName()) {
556 1
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
557 1
            $params['scope'] = $nodeInfo->getScope();
558 1
        }
559
560 6
        if (0 != $startLevel) {
561 2
            $sql->andWhere($options->getLevelColumnName() . ' >= :startLevel');
562
563 2
            $params['startLevel'] = $nodeInfo->getLevel() + (int) $startLevel;
564 2
        }
565
566 6
        if (null != $levels) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $levels of type null|integer against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
567 1
            $sql->andWhere($options->getLevelColumnName() . '< :endLevel');
568 1
            $params['endLevel'] = $nodeInfo->getLevel() + (int) $startLevel + abs($levels);
569 1
        }
570
571 6
        if (null != $excludeBranch && null != ($excludeNodeInfo = $this->getNodeInfo($excludeBranch))) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $excludeBranch of type null|integer against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
572 1
            $sql->andWhere('(' . $options->getLeftColumnName() . ' BETWEEN :left AND :exLeftMinusOne'
573 1
                . ') OR (' . $options->getLeftColumnName() . ' BETWEEN :exRightPlusOne AND :right)')
574 1
                ->andWhere('(' . $options->getRightColumnName() . ' BETWEEN :exRightPlusOne AND :right'
575 1
                    . ') OR (' . $options->getRightColumnName() . ' BETWEEN :left AND :exLeftMinusOne)');
576
577 1
            $params['left']           = $nodeInfo->getLeft();
578 1
            $params['exLeftMinusOne'] = $excludeNodeInfo->getLeft() - 1;
579 1
            $params['exRightPlusOne'] = $excludeNodeInfo->getRight() + 1;
580 1
            $params['right']          = $nodeInfo->getRight();
581 1
        } else {
582 5
            $sql->andWhere($options->getLeftColumnName() . ' >= :left')
583 5
                ->andWhere($options->getRightColumnName() . ' <= :right');
584
585 5
            $params['left']  = $nodeInfo->getLeft();
586 5
            $params['right'] = $nodeInfo->getRight();
587
        }
588
589 6
        $stmt = $connection->executeQuery($sql, $params);
590
591 6
        $result = $stmt->fetchAll();
592
593 6
        return (0 < count($result)) ? $result : array();
594
    }
595
}
596