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

Zend1::moveBranch()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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