Passed
Branch master (9026fd)
by Bartko
02:45
created

Validator::_rebuild()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 16
c 0
b 0
f 0
nc 6
nop 4
dl 0
loc 27
rs 9.1111
ccs 16
cts 16
cp 1
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace StefanoTree\NestedSet\Validator;
6
7
use Exception;
8
use StefanoTree\Exception\TreeIsBrokenException;
9
use StefanoTree\Exception\ValidationException;
10
use StefanoTree\NestedSet\Manipulator\ManipulatorInterface;
11
use StefanoTree\NestedSet\NodeInfo;
12
13
class Validator implements ValidatorInterface
14
{
15
    private $manipulator = null;
16
17
    /**
18
     * @param ManipulatorInterface $manipulator
19
     */
20 8
    public function __construct(ManipulatorInterface $manipulator)
21
    {
22 8
        $this->manipulator = $manipulator;
23
    }
24
25
    /**
26
     * @return ManipulatorInterface
27
     */
28 8
    private function getManipulator(): ManipulatorInterface
29
    {
30 8
        return $this->manipulator;
31
    }
32
33
    /**
34
     * {@inheritdoc}
35
     */
36 5
    public function isValid($rootNodeId): bool
37
    {
38 5
        $adapter = $this->getManipulator();
39
40 5
        $adapter->beginTransaction();
41
42
        try {
43 5
            $adapter->lockTree();
44
45 5
            $rootNodeInfo = $this->getManipulator()->getNodeInfo($rootNodeId);
46
47 5
            if (!$rootNodeInfo instanceof NodeInfo) {
48 1
                throw new ValidationException('Node does not exists.');
49
            }
50
51 4
            $this->_checkIfNodeIsRootNode($rootNodeInfo);
52 2
            $this->_rebuild($rootNodeInfo, true);
53
54 1
            $adapter->commitTransaction();
55 4
        } catch (TreeIsBrokenException $e) {
56 1
            $adapter->rollbackTransaction();
57
58 1
            return false;
59 3
        } catch (Exception $e) {
60 3
            $adapter->rollbackTransaction();
61
62 3
            throw $e;
63
        }
64
65 1
        return true;
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71 3
    public function rebuild($rootNodeId): void
72
    {
73 3
        $adapter = $this->getManipulator();
74
75 3
        $adapter->beginTransaction();
76
77
        try {
78 3
            $adapter->lockTree();
79
80 3
            $rootNodeInfo = $this->getManipulator()->getNodeInfo($rootNodeId);
81
82 3
            if (!$rootNodeInfo instanceof NodeInfo) {
83 1
                throw new ValidationException('Node does not exists.');
84
            }
85
86 2
            $this->_checkIfNodeIsRootNode($rootNodeInfo);
87 1
            $this->_rebuild($rootNodeInfo);
88
89 1
            $adapter->commitTransaction();
90 2
        } catch (Exception $e) {
91 2
            $adapter->rollbackTransaction();
92
93 2
            throw $e;
94
        }
95
    }
96
97
    /**
98
     * @param NodeInfo $parentNodeInfo
99
     * @param bool     $onlyValidate
100
     * @param int      $left
101
     * @param int      $level
102
     *
103
     * @throws TreeIsBrokenException if tree is broken and $onlyValidate is true
104
     *
105
     * @return int
106
     */
107 3
    private function _rebuild(NodeInfo $parentNodeInfo, bool $onlyValidate = false, int $left = 1, int $level = 0): int
108
    {
109 3
        $adapter = $this->getManipulator();
110
111 3
        $right = $left + 1;
112
113 3
        $children = $adapter->getChildrenNodeInfo($parentNodeInfo->getId());
114
115 3
        foreach ($children as $childNode) {
116 3
            $right = $this->_rebuild($childNode, $onlyValidate, $right, $level + 1);
117
        }
118
119 3
        if ($parentNodeInfo->getLeft() != $left
120 1
            || $parentNodeInfo->getRight() != $right
121 3
            || $parentNodeInfo->getLevel() != $level) {
122 2
            $parentNodeInfo->setLeft($left);
123 2
            $parentNodeInfo->setRight($right);
124 2
            $parentNodeInfo->setLevel($level);
125
126 2
            if ($onlyValidate) {
127 1
                throw new TreeIsBrokenException();
128
            } else {
129 1
                $adapter->updateNodeMetadata($parentNodeInfo);
130
            }
131
        }
132
133 2
        return $right + 1;
134
    }
135
136
    /**
137
     * @param NodeInfo $node
138
     *
139
     * @throws ValidationException
140
     */
141 6
    private function _checkIfNodeIsRootNode(NodeInfo $node): void
142
    {
143 6
        if (!$node->isRoot()) {
144 3
            throw new ValidationException('Given node is not root node.');
145
        }
146
    }
147
}
148