Completed
Push — master ( c9036e...5033a3 )
by Bartko
05:59
created

Doctrine2DBAL::getOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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
    public function __construct(Options $options, DbConnection $connection)
23
    {
24
        $this->options = $options;
25
        $this->connection = $connection;
26
    }
27
28
    /**
29
     * @return Options
30
     */
31
    private function getOptions()
32
    {
33
        return $this->options;
34
    }
35
36
    /**
37
     * @return DbConnection
38
     */
39
    private function getConnection()
40
    {
41
        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
    private function cleanData(array $data)
52
    {
53
        $options = $this->getOptions();
54
55
        $disallowedDataKeys = array(
56
            $options->getIdColumnName(),
57
            $options->getLeftColumnName(),
58
            $options->getRightColumnName(),
59
            $options->getLevelColumnName(),
60
            $options->getParentIdColumnName(),
61
            $options->getScopeColumnName(),
62
        );
63
64
        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
    public function getBlankDbSelect()
72
    {
73
        $queryBuilder = $this->getConnection()
74
            ->createQueryBuilder();
75
76
        $queryBuilder->select('*')
77
            ->from($this->getOptions()->getTableName(), null);
78
79
        return $queryBuilder;
80
    }
81
82
    /**
83
     * @param QueryBuilder $dbSelect
84
     * @return void
85
     */
86
    public function setDefaultDbSelect(QueryBuilder $dbSelect)
87
    {
88
        $this->defaultDbSelect = $dbSelect;
89
    }
90
91
    /**
92
     * Return clone of default db select
93
     * @return QueryBuilder
94
     */
95
    public function getDefaultDbSelect()
96
    {
97
        if (null === $this->defaultDbSelect) {
98
            $this->defaultDbSelect = $this->getBlankDbSelect();
99
        }
100
101
        $dbSelect = clone $this->defaultDbSelect;
102
103
        return $dbSelect;
104
    }
105
106
    public function lockTree()
107
    {
108
        $options = $this->getOptions();
109
110
        $connection = $this->getConnection();
111
112
        $sql = $this->getBlankDbSelect();
113
        $sql->select($options->getIdColumnName() . ' AS i');
114
115
        $sql = $sql->getSQL() . ' FOR UPDATE';
116
117
        $connection->executeQuery($sql);
118
    }
119
120
    public function beginTransaction()
121
    {
122
        $this->getConnection()
123
            ->beginTransaction();
124
    }
125
126
    public function commitTransaction()
127
    {
128
        $this->getConnection()
129
            ->commit();
130
    }
131
132
    public function rollbackTransaction()
133
    {
134
        $this->getConnection()
135
            ->rollBack();
136
    }
137
138
    public function update($nodeId, array $data)
139
    {
140
        $options = $this->getOptions();
141
142
        $connection = $this->getConnection();
143
144
        $data = $this->cleanData($data);
145
146
        $sql = $connection->createQueryBuilder();
147
148
        $sql->update($options->getTableName(), null)
149
            ->where($options->getIdColumnName() . ' = :' . $options->getIdColumnName());
150
151
        foreach ($data as $key => $value) {
152
            $sql->set($connection->quoteIdentifier($key), ':' . $key);
153
        }
154
155
        $data[$options->getIdColumnName()] = $nodeId;
156
157
        $connection->executeUpdate($sql, $data);
158
    }
159
160
    public function insert(NodeInfo $nodeInfo, array $data)
161
    {
162
        $options = $this->getOptions();
163
164
        $connection = $this->getConnection();
165
166
        $data[$options->getParentIdColumnName()] = $nodeInfo->getParentId();
167
        $data[$options->getLevelColumnName()]    = $nodeInfo->getLevel();
168
        $data[$options->getLeftColumnName()]     = $nodeInfo->getLeft();
169
        $data[$options->getRightColumnName()]    = $nodeInfo->getRight();
170
171
        if ($options->getScopeColumnName()) {
172
            $data[$options->getScopeColumnName()] = $nodeInfo->getScope();
173
        }
174
175
        $connection->insert($options->getTableName(), $data);
176
177
        return $connection->lastInsertId($options->getSequenceName());
178
    }
179
180
    public function delete($nodeId)
181
    {
182
        $options = $this->getOptions();
183
184
        $connection = $this->getConnection();
185
186
        $sql = $connection->createQueryBuilder();
187
        $sql->delete($options->getTableName())
188
            ->where($options->getIdColumnName() . ' = :id');
189
190
        $params = array(
191
            ':id' => $nodeId,
192
        );
193
194
        $connection->executeQuery($sql, $params);
195
    }
196
197
    public function moveLeftIndexes($fromIndex, $shift, $scope = null)
198
    {
199
        $options = $this->getOptions();
200
201
        if (0 == $shift) {
202
            return;
203
        }
204
205
        $connection = $this->getConnection();
206
207
        $sql = $connection->createQueryBuilder();
208
        $sql->update($options->getTableName())
209
            ->set($options->getLeftColumnName(), $options->getLeftColumnName() . ' + :shift')
210
            ->where($options->getLeftColumnName() . ' > :fromIndex');
211
212
        $params = array(
213
            ':shift' => $shift,
214
            ':fromIndex' => $fromIndex,
215
        );
216
217
        if ($options->getScopeColumnName()) {
218
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
219
            $params[':scope'] = $scope;
220
        }
221
222
        $connection->executeUpdate($sql, $params);
223
    }
224
225
    public function moveRightIndexes($fromIndex, $shift, $scope = null)
226
    {
227
        $options = $this->getOptions();
228
229
        if (0 == $shift) {
230
            return;
231
        }
232
233
        $connection = $this->getConnection();
234
235
        $sql = $connection->createQueryBuilder();
236
        $sql->update($options->getTableName())
237
            ->set($options->getRightColumnName(), $options->getRightColumnName() . ' + :shift')
238
            ->where($options->getRightColumnName() . ' > :fromIndex');
239
240
        $params = array(
241
            ':shift' => $shift,
242
            ':fromIndex' => $fromIndex,
243
        );
244
245
        if ($options->getScopeColumnName()) {
246
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
247
            $params[':scope'] = $scope;
248
        }
249
250
        $connection->executeUpdate($sql, $params);
251
    }
252
253
    public function updateParentId($nodeId, $newParentId)
254
    {
255
        $options = $this->getOptions();
256
257
        $connection = $this->getConnection();
258
259
        $sql = $connection->createQueryBuilder();
260
        $sql->update($options->getTableName())
261
            ->set($options->getParentIdColumnName(), ':parentId')
262
            ->where($options->getIdColumnName() . ' = :nodeId');
263
264
        $params = array(
265
            ':parentId' => $newParentId,
266
            ':nodeId' => $nodeId,
267
        );
268
269
        $connection->executeUpdate($sql, $params);
270
    }
271
272
    public function updateLevels($leftIndexFrom, $rightIndexTo, $shift, $scope = null)
273
    {
274
        $options = $this->getOptions();
275
276
        if (0 == $shift) {
277
            return;
278
        }
279
280
        $connection = $this->getConnection();
281
282
        $sql = $connection->createQueryBuilder();
283
        $sql->update($options->getTableName())
284
            ->set($options->getLevelColumnName(), $options->getLevelColumnName() . ' + :shift')
285
            ->where($options->getLeftColumnName() . ' >= :leftFrom'
286
                . ' AND ' . $options->getRightColumnName() . ' <= :rightTo');
287
288
        $params = array(
289
            ':shift' => $shift,
290
            ':leftFrom' => $leftIndexFrom,
291
            ':rightTo' => $rightIndexTo,
292
        );
293
294
        if ($options->getScopeColumnName()) {
295
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
296
            $params[':scope'] = $scope;
297
        }
298
299
        $connection->executeUpdate($sql, $params);
300
    }
301
302
    public function moveBranch($leftIndexFrom, $rightIndexTo, $shift, $scope = null)
303
    {
304
        if (0 == $shift) {
305
            return;
306
        }
307
308
        $options = $this->getOptions();
309
310
        $connection = $this->getConnection();
311
312
        $sql = $connection->createQueryBuilder();
313
        $sql->update($options->getTableName())
314
            ->set($options->getLeftColumnName(), $options->getLeftColumnName() . ' + :shift')
315
            ->set($options->getRightColumnName(), $options->getRightColumnName() . ' + :shift')
316
            ->where($options->getLeftColumnName() . ' >= :leftFrom'
317
                . ' AND ' . $options->getRightColumnName() . ' <= :rightTo');
318
319
        $params = array(
320
            ':shift' => $shift,
321
            ':leftFrom' => $leftIndexFrom,
322
            ':rightTo' => $rightIndexTo,
323
        );
324
325
        if ($options->getScopeColumnName()) {
326
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
327
            $params[':scope'] = $scope;
328
        }
329
330
        $connection->executeUpdate($sql, $params);
331
    }
332
333
    public function getRoots($scope = null)
334
    {
335
        $options = $this->getOptions();
336
337
        $connection = $this->getConnection();
338
339
        $sql = $this->getBlankDbSelect();
340
        $sql->where($options->getParentIdColumnName() . ' IS NULL');
341
        $sql->orderBy($options->getIdColumnName());
342
343
        $params = array();
344
345
        if (null != $scope && $options->getScopeColumnName()) {
346
            $sql->where($options->getScopeColumnName() . ' = :scope');
347
            $params[':scope'] = $scope;
348
        }
349
350
        $stmt = $connection->executeQuery($sql, $params);
351
352
        $node = $stmt->fetchAll();
353
354
        return $node;
355
    }
356
357
    public function getRoot($scope = null)
358
    {
359
        $roots = $this->getRoots($scope);
360
        return ($roots) ?  $roots[0] : array();
361
    }
362
363
    public function getNode($nodeId)
364
    {
365
        $options = $this->getOptions();
366
367
        $nodeId = (int) $nodeId;
368
369
        $connection = $this->getConnection();
370
371
372
        $sql = $this->getDefaultDbSelect();
373
        $sql->where($options->getIdColumnName() . ' = :' . $options->getIdColumnName());
374
375
        $params = array(
376
            $options->getIdColumnName() => $nodeId,
377
        );
378
379
        $stmt = $connection->executeQuery($sql, $params);
380
381
        $node = $stmt->fetch();
382
383
        return is_array($node) ? $node : null;
384
    }
385
386
    /**
387
     * @param array $data
388
     * @return NodeInfo
389
     */
390
    private function _buildNodeInfoObject(array $data)
391
    {
392
        $options = $this->getOptions();
393
394
        $id        = $data[$options->getIdColumnName()];
395
        $parentId  = $data[$options->getParentIdColumnName()];
396
        $level     = $data[$options->getLevelColumnName()];
397
        $left      = $data[$options->getLeftColumnName()];
398
        $right     = $data[$options->getRightColumnName()];
399
400
        if (isset($data[$options->getScopeColumnName()])) {
401
            $scope = $data[$options->getScopeColumnName()];
402
        } else {
403
            $scope = null;
404
        }
405
406
        return new NodeInfo($id, $parentId, $level, $left, $right, $scope);
407
    }
408
409
    public function getNodeInfo($nodeId)
410
    {
411
        $options = $this->getOptions();
412
413
        $nodeId = (int) $nodeId;
414
415
        $connection = $this->getConnection();
416
417
418
        $sql = $this->getBlankDbSelect();
419
        $sql->where($options->getIdColumnName() . ' = :' . $options->getIdColumnName());
420
421
        $params = array(
422
            $options->getIdColumnName() => $nodeId,
423
        );
424
425
        $stmt = $connection->executeQuery($sql, $params);
426
427
        $node = $stmt->fetch();
428
429
        $data = is_array($node) ? $node : null;
430
431
        $result = ($data) ? $this->_buildNodeInfoObject($data) : null;
432
433
        return $result;
434
    }
435
436
    public function getChildrenNodeInfo($parentNodeId)
437
    {
438
        $connection = $this->getConnection();
439
        $options = $this->getOptions();
440
441
        $queryBuilder = $connection->createQueryBuilder();
442
443
        $columns = array(
444
            $options->getIdColumnName(),
445
            $options->getLeftColumnName(),
446
            $options->getRightColumnName(),
447
            $options->getParentIdColumnName(),
448
            $options->getLevelColumnName(),
449
        );
450
451
        $sql = $queryBuilder->select($columns)
452
            ->from($options->getTableName())
453
            ->where($options->getParentIdColumnName() . ' = :parentId')
454
            ->orderBy($options->getLeftColumnName(), 'ASC');
455
456
        $params = array(
457
            'parentId' => $parentNodeId,
458
        );
459
460
        $stmt = $connection->executeQuery($sql, $params);
461
462
        $data = $stmt->fetchAll();
463
464
        $result = array();
465
466
        foreach ($data as $nodeData) {
467
            $result[] = $this->_buildNodeInfoObject($nodeData);
468
        }
469
470
        return $result;
471
    }
472
473
    public function updateNodeMetadata(NodeInfo $nodeInfo)
474
    {
475
        $options = $this->getOptions();
476
477
        $connection = $this->getConnection();
478
479
        $sql = $connection->createQueryBuilder();
480
        $sql->update($options->getTableName())
481
            ->set($options->getRightColumnName(), $nodeInfo->getRight())
482
            ->set($options->getLeftColumnName(), $nodeInfo->getLeft())
483
            ->set($options->getLevelColumnName(), $nodeInfo->getLevel())
484
            ->where($options->getIdColumnName() . ' = :nodeId');
485
486
        $params = array(
487
            ':nodeId' => $nodeInfo->getId(),
488
        );
489
490
        $connection->executeUpdate($sql, $params);
491
    }
492
493
    public function getPath($nodeId, $startLevel = 0, $excludeLastNode = false)
494
    {
495
        $options = $this->getOptions();
496
497
        $startLevel = (int) $startLevel;
498
499
        // node does not exist
500
        $nodeInfo = $this->getNodeInfo($nodeId);
501
        if (!$nodeInfo) {
502
            return array();
503
        }
504
505
        $connection = $this->getConnection();
506
507
        $sql = $this->getDefaultDbSelect();
508
        $params = array();
509
510
        if ($options->getScopeColumnName()) {
511
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
512
            $params['scope'] = $nodeInfo->getScope();
513
        }
514
515
        $sql->andWhere($options->getLeftColumnName() . ' <= :leftIndex')
516
            ->andWhere($options->getRightColumnName() . ' >= :rightIndex')
517
            ->orderBy($options->getLeftColumnName(), 'ASC');
518
519
        $params['leftIndex'] = $nodeInfo->getLeft();
520
        $params['rightIndex'] = $nodeInfo->getRight();
521
522
        if (0 < $startLevel) {
523
            $sql->andWhere($options->getLevelColumnName() . ' >= :startLevel');
524
525
            $params['startLevel'] = $startLevel;
526
        }
527
528
        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
            $sql->andWhere($options->getLevelColumnName() . ' < :level');
530
531
            $params['level'] = $nodeInfo->getLevel();
532
        }
533
534
        $stmt = $connection->executeQuery($sql, $params);
535
536
        $result = $stmt->fetchAll();
537
538
        return (is_array($result)) ? $result : array();
539
    }
540
541
    public function getDescendants($nodeId = 1, $startLevel = 0, $levels = null, $excludeBranch = null)
542
    {
543
        $options = $this->getOptions();
544
545
        if (!$nodeInfo = $this->getNodeInfo($nodeId)) {
546
            return array();
547
        }
548
549
        $connection = $this->getConnection();
550
        $sql = $this->getDefaultDbSelect();
551
        $sql->orderBy($options->getLeftColumnName(), 'ASC');
552
553
        $params = array();
554
555
        if ($options->getScopeColumnName()) {
556
            $sql->andWhere($options->getScopeColumnName() . ' = :scope');
557
            $params['scope'] = $nodeInfo->getScope();
558
        }
559
560
        if (0 != $startLevel) {
561
            $sql->andWhere($options->getLevelColumnName() . ' >= :startLevel');
562
563
            $params['startLevel'] = $nodeInfo->getLevel() + (int) $startLevel;
564
        }
565
566
        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
            $sql->andWhere($options->getLevelColumnName() . '< :endLevel');
568
            $params['endLevel'] = $nodeInfo->getLevel() + (int) $startLevel + abs($levels);
569
        }
570
571
        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
            $sql->andWhere('(' . $options->getLeftColumnName() . ' BETWEEN :left AND :exLeftMinusOne'
573
                . ') OR (' . $options->getLeftColumnName() . ' BETWEEN :exRightPlusOne AND :right)')
574
                ->andWhere('(' . $options->getRightColumnName() . ' BETWEEN :exRightPlusOne AND :right'
575
                    . ') OR (' . $options->getRightColumnName() . ' BETWEEN :left AND :exLeftMinusOne)');
576
577
            $params['left']           = $nodeInfo->getLeft();
578
            $params['exLeftMinusOne'] = $excludeNodeInfo->getLeft() - 1;
579
            $params['exRightPlusOne'] = $excludeNodeInfo->getRight() + 1;
580
            $params['right']          = $nodeInfo->getRight();
581
        } else {
582
            $sql->andWhere($options->getLeftColumnName() . ' >= :left')
583
                ->andWhere($options->getRightColumnName() . ' <= :right');
584
585
            $params['left']  = $nodeInfo->getLeft();
586
            $params['right'] = $nodeInfo->getRight();
587
        }
588
589
        $stmt = $connection->executeQuery($sql, $params);
590
591
        $result = $stmt->fetchAll();
592
593
        return (0 < count($result)) ? $result : array();
594
    }
595
}
596