Completed
Push — master ( 2b0446...afde37 )
by Bartko
04:01 queued 01:40
created

Doctrine2DBAL::rollbackTransaction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace StefanoTree\NestedSet\Adapter;
6
7
use Doctrine\DBAL\Connection as DbConnection;
8
use Doctrine\DBAL\Query\QueryBuilder;
9
use StefanoTree\NestedSet\NodeInfo;
10
use StefanoTree\NestedSet\Options;
11
12
class Doctrine2DBAL extends AdapterAbstract implements AdapterInterface
13
{
14
    private $connection;
15
16
    /**
17
     * @param Options      $options
18
     * @param DbConnection $connection
19
     */
20 55
    public function __construct(Options $options, DbConnection $connection)
21
    {
22 55
        $this->setOptions($options);
23 55
        $this->setConnection($connection);
24 55
    }
25
26
    /**
27
     * @param DbConnection $dbAdapter
28
     */
29 55
    protected function setConnection(DbConnection $dbAdapter): void
30
    {
31 55
        $this->connection = $dbAdapter;
32 55
    }
33
34
    /**
35
     * @return DbConnection
36
     */
37 52
    private function getConnection(): DbConnection
38
    {
39 52
        return $this->connection;
40
    }
41
42
    /**
43
     * Return base db select without any join, etc.
44
     *
45
     * @return QueryBuilder
46
     */
47 32
    public function getBlankDbSelect(): QueryBuilder
48
    {
49 32
        $queryBuilder = $this->getConnection()
50 32
                             ->createQueryBuilder();
51
52 32
        $queryBuilder->select(sprintf('%s.*', $this->getOptions()->getTableName()))
53 32
                     ->from($this->getOptions()->getTableName());
54
55 32
        return $queryBuilder;
56
    }
57
58
    /**
59
     * Return default db select. Always new instance.
60
     *
61
     * @return QueryBuilder
62
     */
63 17
    public function getDefaultDbSelect(): QueryBuilder
64
    {
65 17
        return $this->getDbSelectBuilder()();
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71 1
    public function lockTree(): void
72
    {
73 1
        $options = $this->getOptions();
74
75 1
        $connection = $this->getConnection();
76
77 1
        $sql = $this->getBlankDbSelect();
78 1
        $sql->select($options->getIdColumnName(true).' AS i');
79
80 1
        $sql = $sql->getSQL().' FOR UPDATE';
81
82 1
        $connection->executeQuery($sql);
83 1
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 1
    public function beginTransaction(): void
89
    {
90 1
        $this->getConnection()
91 1
             ->beginTransaction();
92 1
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97 1
    public function commitTransaction(): void
98
    {
99 1
        $this->getConnection()
100 1
             ->commit();
101 1
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106 1
    public function rollbackTransaction(): void
107
    {
108 1
        $this->getConnection()
109 1
             ->rollBack();
110 1
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115 3
    public function update($nodeId, array $data): void
116
    {
117 3
        $options = $this->getOptions();
118
119 3
        $connection = $this->getConnection();
120
121 3
        $data = $this->cleanData($data);
122
123 3
        $sql = $connection->createQueryBuilder();
124
125 3
        $sql->update($options->getTableName(), null)
126 3
            ->where($options->getIdColumnName().' = :'.$options->getIdColumnName());
127
128 3
        foreach ($data as $key => $value) {
129 3
            $sql->set($connection->quoteIdentifier($key), ':'.$key);
130
        }
131
132 3
        $data[$options->getIdColumnName()] = $nodeId;
133
134 3
        $connection->executeUpdate($sql->getSQL(), $data);
135 3
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140 3
    public function insert(NodeInfo $nodeInfo, array $data)
141
    {
142 3
        $options = $this->getOptions();
143
144 3
        $connection = $this->getConnection();
145
146 3
        $data[$options->getParentIdColumnName()] = $nodeInfo->getParentId();
147 3
        $data[$options->getLevelColumnName()] = $nodeInfo->getLevel();
148 3
        $data[$options->getLeftColumnName()] = $nodeInfo->getLeft();
149 3
        $data[$options->getRightColumnName()] = $nodeInfo->getRight();
150
151 3
        if ($options->getScopeColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options->getScopeColumnName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
152 1
            $data[$options->getScopeColumnName()] = $nodeInfo->getScope();
153
        }
154
155 3
        $connection->insert($options->getTableName(), $data);
156
157 3
        return $connection->lastInsertId($options->getSequenceName());
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163 2
    public function delete($nodeId): void
164
    {
165 2
        $options = $this->getOptions();
166
167 2
        $connection = $this->getConnection();
168
169 2
        $sql = $connection->createQueryBuilder();
170 2
        $sql->delete($options->getTableName())
171 2
            ->where($options->getIdColumnName().' = :id');
172
173
        $params = array(
174 2
            ':id' => $nodeId,
175
        );
176
177 2
        $connection->executeQuery($sql->getSQL(), $params);
178 2
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183 2
    public function moveLeftIndexes($fromIndex, $shift, $scope = null): void
184
    {
185 2
        $options = $this->getOptions();
186
187 2
        if (0 == $shift) {
188
            return;
189
        }
190
191 2
        $connection = $this->getConnection();
192
193 2
        $sql = $connection->createQueryBuilder();
194 2
        $sql->update($options->getTableName())
195 2
            ->set($options->getLeftColumnName(), $options->getLeftColumnName().' + :shift')
196 2
            ->where($options->getLeftColumnName().' > :fromIndex');
197
198
        $params = array(
199 2
            ':shift' => $shift,
200 2
            ':fromIndex' => $fromIndex,
201
        );
202
203 2
        if ($options->getScopeColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options->getScopeColumnName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
204 1
            $sql->andWhere($options->getScopeColumnName().' = :scope');
205 1
            $params[':scope'] = $scope;
206
        }
207
208 2
        $connection->executeUpdate($sql->getSQL(), $params);
209 2
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214 2
    public function moveRightIndexes($fromIndex, $shift, $scope = null): void
215
    {
216 2
        $options = $this->getOptions();
217
218 2
        if (0 == $shift) {
219
            return;
220
        }
221
222 2
        $connection = $this->getConnection();
223
224 2
        $sql = $connection->createQueryBuilder();
225 2
        $sql->update($options->getTableName())
226 2
            ->set($options->getRightColumnName(), $options->getRightColumnName().' + :shift')
227 2
            ->where($options->getRightColumnName().' > :fromIndex');
228
229
        $params = array(
230 2
            ':shift' => $shift,
231 2
            ':fromIndex' => $fromIndex,
232
        );
233
234 2
        if ($options->getScopeColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options->getScopeColumnName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
235 1
            $sql->andWhere($options->getScopeColumnName().' = :scope');
236 1
            $params[':scope'] = $scope;
237
        }
238
239 2
        $connection->executeUpdate($sql->getSQL(), $params);
240 2
    }
241
242
    /**
243
     * {@inheritdoc}
244
     */
245 1
    public function updateParentId($nodeId, $newParentId): void
246
    {
247 1
        $options = $this->getOptions();
248
249 1
        $connection = $this->getConnection();
250
251 1
        $sql = $connection->createQueryBuilder();
252 1
        $sql->update($options->getTableName())
253 1
            ->set($options->getParentIdColumnName(), ':parentId')
254 1
            ->where($options->getIdColumnName().' = :nodeId');
255
256
        $params = array(
257 1
            ':parentId' => $newParentId,
258 1
            ':nodeId' => $nodeId,
259
        );
260
261 1
        $connection->executeUpdate($sql->getSQL(), $params);
262 1
    }
263
264
    /**
265
     * {@inheritdoc}
266
     */
267 2
    public function updateLevels(int $leftIndexFrom, int $rightIndexTo, int $shift, $scope = null): void
268
    {
269 2
        $options = $this->getOptions();
270
271 2
        if (0 == $shift) {
272
            return;
273
        }
274
275 2
        $connection = $this->getConnection();
276
277 2
        $sql = $connection->createQueryBuilder();
278 2
        $sql->update($options->getTableName())
279 2
            ->set($options->getLevelColumnName(), $options->getLevelColumnName().' + :shift')
280 2
            ->where($options->getLeftColumnName().' >= :leftFrom'
281 2
                    .' AND '.$options->getRightColumnName().' <= :rightTo');
282
283
        $params = array(
284 2
            ':shift' => $shift,
285 2
            ':leftFrom' => $leftIndexFrom,
286 2
            ':rightTo' => $rightIndexTo,
287
        );
288
289 2
        if ($options->getScopeColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options->getScopeColumnName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
290 1
            $sql->andWhere($options->getScopeColumnName().' = :scope');
291 1
            $params[':scope'] = $scope;
292
        }
293
294 2
        $connection->executeUpdate($sql->getSQL(), $params);
295 2
    }
296
297
    /**
298
     * {@inheritdoc}
299
     */
300 2
    public function moveBranch(int $leftIndexFrom, int $rightIndexTo, int $shift, $scope = null): void
301
    {
302 2
        if (0 == $shift) {
303
            return;
304
        }
305
306 2
        $options = $this->getOptions();
307
308 2
        $connection = $this->getConnection();
309
310 2
        $sql = $connection->createQueryBuilder();
311 2
        $sql->update($options->getTableName())
312 2
            ->set($options->getLeftColumnName(), $options->getLeftColumnName().' + :shift')
313 2
            ->set($options->getRightColumnName(), $options->getRightColumnName().' + :shift')
314 2
            ->where($options->getLeftColumnName().' >= :leftFrom'
315 2
                    .' AND '.$options->getRightColumnName().' <= :rightTo');
316
317
        $params = array(
318 2
            ':shift' => $shift,
319 2
            ':leftFrom' => $leftIndexFrom,
320 2
            ':rightTo' => $rightIndexTo,
321
        );
322
323 2
        if ($options->getScopeColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options->getScopeColumnName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
324 1
            $sql->andWhere($options->getScopeColumnName().' = :scope');
325 1
            $params[':scope'] = $scope;
326
        }
327
328 2
        $connection->executeUpdate($sql->getSQL(), $params);
329 2
    }
330
331
    /**
332
     * {@inheritdoc}
333
     */
334 4
    public function getRoots($scope = null): array
335
    {
336 4
        $options = $this->getOptions();
337
338 4
        $connection = $this->getConnection();
339
340 4
        $sql = $this->getBlankDbSelect();
341 4
        $sql->where($options->getParentIdColumnName(true).' IS NULL');
342 4
        $sql->orderBy($options->getIdColumnName());
343
344 4
        $params = array();
345
346 4
        if (null != $scope && $options->getScopeColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options->getScopeColumnName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
347 1
            $sql->where($options->getScopeColumnName(true).' = :scope');
348 1
            $params[':scope'] = $scope;
349
        }
350
351 4
        $stmt = $connection->executeQuery($sql->getSQL(), $params);
352
353 4
        $node = $stmt->fetchAll();
354
355 4
        return $node;
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     */
361 2
    public function getRoot($scope = null): array
362
    {
363 2
        $roots = $this->getRoots($scope);
364
365 2
        return ($roots) ? $roots[0] : array();
366
    }
367
368
    /**
369
     * {@inheritdoc}
370
     */
371 2
    public function getNode($nodeId): ?array
372
    {
373 2
        $options = $this->getOptions();
374
375 2
        $nodeId = (int) $nodeId;
376
377 2
        $connection = $this->getConnection();
378
379 2
        $sql = $this->getDefaultDbSelect();
380 2
        $sql->where($options->getIdColumnName(true).' = :id');
381
382
        $params = array(
383 2
            'id' => $nodeId,
384
        );
385
386 2
        $stmt = $connection->executeQuery($sql->getSQL(), $params);
387
388 2
        $node = $stmt->fetch();
389
390 2
        return is_array($node) ? $node : null;
391
    }
392
393
    /**
394
     * {@inheritdoc}
395
     */
396 19
    public function getNodeInfo($nodeId): ?NodeInfo
397
    {
398 19
        $options = $this->getOptions();
399
400 19
        $nodeId = (int) $nodeId;
401
402 19
        $connection = $this->getConnection();
403
404 19
        $sql = $this->getBlankDbSelect();
405 19
        $sql->where($options->getIdColumnName(true).' = :id');
406
407
        $params = array(
408 19
            'id' => $nodeId,
409
        );
410
411 19
        $stmt = $connection->executeQuery($sql->getSQL(), $params);
412
413 19
        $node = $stmt->fetch();
414
415 19
        $data = is_array($node) ? $node : null;
416
417 19
        $result = ($data) ? $this->_buildNodeInfoObject($data) : null;
418
419 19
        return $result;
420
    }
421
422
    /**
423
     * {@inheritdoc}
424
     */
425 4
    public function getChildrenNodeInfo($parentNodeId): array
426
    {
427 4
        $connection = $this->getConnection();
428 4
        $options = $this->getOptions();
429
430 4
        $sql = $this->getBlankDbSelect();
431
432 4
        $sql = $sql->where($options->getParentIdColumnName(true).' = :parentId')
433 4
                   ->orderBy($options->getLeftColumnName(true), 'ASC');
434
435
        $params = array(
436 4
            'parentId' => $parentNodeId,
437
        );
438
439 4
        $stmt = $connection->executeQuery($sql->getSQL(), $params);
440
441 4
        $data = $stmt->fetchAll();
442
443 4
        $result = array();
444
445 4
        foreach ($data as $nodeData) {
446 3
            $result[] = $this->_buildNodeInfoObject($nodeData);
447
        }
448
449 4
        return $result;
450
    }
451
452
    /**
453
     * {@inheritdoc}
454
     */
455 2
    public function updateNodeMetadata(NodeInfo $nodeInfo): void
456
    {
457 2
        $options = $this->getOptions();
458
459 2
        $connection = $this->getConnection();
460
461 2
        $sql = $connection->createQueryBuilder();
462 2
        $sql->update($options->getTableName())
463 2
            ->set($options->getRightColumnName(), $nodeInfo->getRight())
464 2
            ->set($options->getLeftColumnName(), $nodeInfo->getLeft())
465 2
            ->set($options->getLevelColumnName(), $nodeInfo->getLevel())
466 2
            ->where($options->getIdColumnName().' = :nodeId');
467
468
        $params = array(
469 2
            ':nodeId' => $nodeInfo->getId(),
470
        );
471
472 2
        $connection->executeUpdate($sql->getSQL(), $params);
473 2
    }
474
475
    /**
476
     * {@inheritdoc}
477
     */
478 6
    public function getAncestors($nodeId, int $startLevel = 0, int $excludeLastNLevels = 0): array
479
    {
480 6
        $options = $this->getOptions();
481
482 6
        $startLevel = (int) $startLevel;
483
484
        // node does not exist
485 6
        $nodeInfo = $this->getNodeInfo($nodeId);
486 6
        if (!$nodeInfo) {
487 1
            return array();
488
        }
489
490 5
        $connection = $this->getConnection();
491
492 5
        $sql = $this->getDefaultDbSelect();
493 5
        $params = array();
494
495 5
        if ($options->getScopeColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options->getScopeColumnName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
496 2
            $sql->andWhere($options->getScopeColumnName(true).' = :scope');
497 2
            $params['scope'] = $nodeInfo->getScope();
498
        }
499
500 5
        $sql->andWhere($options->getLeftColumnName(true).' <= :leftIndex')
501 5
            ->andWhere($options->getRightColumnName(true).' >= :rightIndex')
502 5
            ->orderBy($options->getLeftColumnName(true), 'ASC');
503
504 5
        $params['leftIndex'] = $nodeInfo->getLeft();
505 5
        $params['rightIndex'] = $nodeInfo->getRight();
506
507 5
        if (0 < $startLevel) {
508 2
            $sql->andWhere($options->getLevelColumnName(true).' >= :startLevel');
509
510 2
            $params['startLevel'] = $startLevel;
511
        }
512
513 5
        if (0 < $excludeLastNLevels) {
514 2
            $sql->andWhere($options->getLevelColumnName(true).' <= :level');
515
516 2
            $params['level'] = $nodeInfo->getLevel() - $excludeLastNLevels;
517
        }
518
519 5
        $stmt = $connection->executeQuery($sql->getSQL(), $params);
520
521 5
        $result = $stmt->fetchAll();
522
523 5
        return (is_array($result)) ? $result : array();
524
    }
525
526
    /**
527
     * {@inheritdoc}
528
     */
529 9
    public function getDescendants($nodeId, int $startLevel = 0, ?int $levels = null, $excludeBranch = null): array
530
    {
531 9
        $options = $this->getOptions();
532
533 9
        if (!$nodeInfo = $this->getNodeInfo($nodeId)) {
534 1
            return array();
535
        }
536
537 8
        $connection = $this->getConnection();
538 8
        $sql = $this->getDefaultDbSelect();
539 8
        $sql->orderBy($options->getLeftColumnName(true), 'ASC');
540
541 8
        $params = array();
542
543 8
        if ($options->getScopeColumnName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options->getScopeColumnName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
544 3
            $sql->andWhere($options->getScopeColumnName(true).' = :scope');
545 3
            $params['scope'] = $nodeInfo->getScope();
546
        }
547
548 8
        if (0 != $startLevel) {
549 3
            $sql->andWhere($options->getLevelColumnName(true).' >= :startLevel');
550
551 3
            $params['startLevel'] = $nodeInfo->getLevel() + (int) $startLevel;
552
        }
553
554 8
        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...
555 2
            $sql->andWhere($options->getLevelColumnName(true).'< :endLevel');
556 2
            $params['endLevel'] = $nodeInfo->getLevel() + (int) $startLevel + abs($levels);
557
        }
558
559 8
        if (null != $excludeBranch && null != ($excludeNodeInfo = $this->getNodeInfo($excludeBranch))) {
560 2
            $sql->andWhere('('.$options->getLeftColumnName(true).' BETWEEN :left AND :exLeftMinusOne'
561 2
                           .') OR ('.$options->getLeftColumnName(true).' BETWEEN :exRightPlusOne AND :right)')
562 2
                ->andWhere('('.$options->getRightColumnName(true).' BETWEEN :exRightPlusOne AND :right'
563 2
                           .') OR ('.$options->getRightColumnName(true).' BETWEEN :left AND :exLeftMinusOne)');
564
565 2
            $params['left'] = $nodeInfo->getLeft();
566 2
            $params['exLeftMinusOne'] = $excludeNodeInfo->getLeft() - 1;
567 2
            $params['exRightPlusOne'] = $excludeNodeInfo->getRight() + 1;
568 2
            $params['right'] = $nodeInfo->getRight();
569
        } else {
570 6
            $sql->andWhere($options->getLeftColumnName(true).' >= :left')
571 6
                ->andWhere($options->getRightColumnName(true).' <= :right');
572
573 6
            $params['left'] = $nodeInfo->getLeft();
574 6
            $params['right'] = $nodeInfo->getRight();
575
        }
576
577 8
        $stmt = $connection->executeQuery($sql->getSQL(), $params);
578
579 8
        $result = $stmt->fetchAll();
580
581 8
        return (0 < count($result)) ? $result : array();
582
    }
583
}
584