Completed
Push — master ( 91af33...2e5d0e )
by Bartko
02:39
created

Doctrine2DBALAdapter::updateLevels()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 2.0009

Importance

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