Completed
Push — develop ( d0fbe3...729812 )
by Bartko
14:43
created

Doctrine2DBALAdapter::update()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 2

Importance

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