Completed
Push — develop ( e8f38f...66df04 )
by Bartko
03:20
created

Zend1::getNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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