Completed
Push — master ( 2b0446...afde37 )
by Bartko
04:01 queued 01:40
created

MoveStrategyAbstract::setTargetNodeInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace StefanoTree\NestedSet\MoveStrategy;
6
7
use StefanoTree\Exception\ValidationException;
8
use StefanoTree\NestedSet\Adapter\AdapterInterface;
9
use StefanoTree\NestedSet\NodeInfo;
10
11
abstract class MoveStrategyAbstract implements MoveStrategyInterface
12
{
13
    private $adapter;
14
15
    private $sourceNodeInfo;
16
    private $targetNodeInfo;
17
18
    /**
19
     * @param AdapterInterface $adapter
20
     */
21 12
    public function __construct(AdapterInterface $adapter)
22
    {
23 12
        $this->adapter = $adapter;
24 12
    }
25
26
    /**
27
     * {@inheritdoc}
28
     */
29 12
    public function move($sourceNodeId, $targetNodeId): void
30
    {
31 12
        $adapter = $this->getAdapter();
32
33 12
        if ($sourceNodeId == $targetNodeId) {
34 1
            throw new ValidationException('Cannot move. Source node and Target node are equal.');
35
        }
36
37 11
        $adapter->beginTransaction();
38
        try {
39 11
            $adapter->lockTree();
40
41 11
            $sourceNodeInfo = $adapter->getNodeInfo($sourceNodeId);
42 11
            $targetNodeInfo = $adapter->getNodeInfo($targetNodeId);
43
44 11
            if (!$sourceNodeInfo) {
45 1
                throw new ValidationException('Cannot move. Source node does not exists.');
46
            }
47
48 10
            if (!$targetNodeInfo) {
49 1
                throw new ValidationException('Cannot move. Target node does not exists.');
50
            }
51
52 9
            $this->setSourceNodeInfo($sourceNodeInfo);
53 9
            $this->setTargetNodeInfo($targetNodeInfo);
54
55 9
            if ($sourceNodeInfo->getScope() != $targetNodeInfo->getScope()) {
56 1
                throw new ValidationException('Cannot move node between scopes.');
57
            }
58
59 8
            $this->canMoveBranch();
60
61 5
            if ($this->isSourceNodeAtRequiredPosition()) {
62 4
                $adapter->commitTransaction();
63
64 4
                return;
65
            }
66
67 5
            $this->updateParentId();
68 5
            $this->updateLevels();
69 5
            $this->makeHole();
70 5
            $this->moveBranchToTheHole();
71 5
            $this->patchHole();
72
73 5
            $adapter->commitTransaction();
74 6
        } catch (\Exception $e) {
75 6
            $adapter->rollbackTransaction();
76
77 6
            throw $e;
78
        }
79 5
    }
80
81
    /**
82
     * Check if can move node.
83
     *
84
     * @throws ValidationException if cannot move branch
85
     */
86
    abstract protected function canMoveBranch(): void;
87
88
    /**
89
     * @return bool
90
     */
91
    abstract protected function isSourceNodeAtRequiredPosition(): bool;
92
93
    /**
94
     * @param NodeInfo $sourceNodeInfo
95
     * @param $newParentId
96
     */
97 5
    protected function _updateParentId(NodeInfo $sourceNodeInfo, $newParentId): void
98
    {
99 5
        if ($sourceNodeInfo->getParentId() != $newParentId) {
100 4
            $this->getAdapter()->updateParentId($sourceNodeInfo->getId(), $newParentId);
101
        }
102 5
    }
103
104
    /**
105
     * Update parent id.
106
     */
107
    abstract protected function updateParentId(): void;
108
109
    /**
110
     * @param NodeInfo $sourceNodeInfo
111
     * @param int      $levelShift
112
     */
113 5
    protected function _updateLevels(NodeInfo $sourceNodeInfo, int $levelShift): void
114
    {
115 5
        if (0 !== $levelShift) {
116 4
            $this->getAdapter()
117 4
                 ->updateLevels(
118 4
                    $sourceNodeInfo->getLeft(),
119 4
                    $sourceNodeInfo->getRight(),
120 4
                    $levelShift,
121 4
                    $sourceNodeInfo->getScope()
122
            );
123
        }
124 5
    }
125
126
    /**
127
     * Update levels.
128
     */
129
    abstract protected function updateLevels(): void;
130
131
    /**
132
     * @param int $holeFromIndex
133
     * @param int $indexShift
134
     * @param $scope
135
     */
136 5
    protected function _makeHole(int $holeFromIndex, int $indexShift, $scope): void
137
    {
138 5
        $this->getAdapter()->moveLeftIndexes($holeFromIndex, $indexShift, $scope);
139 5
        $this->getAdapter()->moveRightIndexes($holeFromIndex, $indexShift, $scope);
140 5
    }
141
142
    /**
143
     * Make hole for moved branch.
144
     */
145
    abstract protected function makeHole(): void;
146
147
    /**
148
     * @param int $leftIndex
149
     * @param int $rightIndex
150
     * @param int $indexShift
151
     * @param $scope
152
     */
153 5
    protected function _moveBranchToTheHole(int $leftIndex, int $rightIndex, int $indexShift, $scope): void
154
    {
155 5
        $this->getAdapter()
156 5
             ->moveBranch($leftIndex, $rightIndex, $indexShift, $scope);
157 5
    }
158
159
    /**
160
     * Move branch to the Hole.
161
     */
162
    abstract protected function moveBranchToTheHole(): void;
163
164
    /**
165
     * @param int $holeFromIndex
166
     * @param int $indexShift
167
     * @param $scope
168
     */
169 5
    protected function _patchHole(int $holeFromIndex, int $indexShift, $scope): void
170
    {
171 5
        $this->getAdapter()
172 5
             ->moveLeftIndexes($holeFromIndex, $indexShift, $scope);
173
174 5
        $this->getAdapter()
175 5
             ->moveRightIndexes($holeFromIndex, $indexShift, $scope);
176 5
    }
177
178
    /**
179
     * Patch hole.
180
     */
181
    abstract protected function patchHole(): void;
182
183
    /**
184
     * @return int
185
     */
186 5
    protected function getIndexShift(): int
187
    {
188 5
        $source = $this->getSourceNodeInfo();
189
190 5
        return $source->getRight() - $source->getLeft() + 1;
191
    }
192
193
    /**
194
     * @return bool
195
     */
196 4
    protected function isMovedUp(): bool
197
    {
198 4
        return ($this->getTargetNodeInfo()->getRight() < $this->getSourceNodeInfo()->getLeft()) ? true : false;
199
    }
200
201
    /**
202
     * @return bool
203
     */
204 5
    protected function isMovedDown(): bool
205
    {
206 5
        return ($this->getSourceNodeInfo()->getRight() < $this->getTargetNodeInfo()->getLeft()) ? true : false;
207
    }
208
209
    /**
210
     * @return bool
211
     */
212 5
    protected function isMovedToRoot(): bool
213
    {
214 5
        $source = $this->getSourceNodeInfo();
215 5
        $target = $this->getTargetNodeInfo();
216
217 5
        return ($source->getLeft() > $target->getLeft() && $source->getRight() < $target->getRight()) ? true : false;
218
    }
219
220
    /**
221
     * @return bool
222
     */
223 8
    protected function isTargetNodeInsideSourceBranch(): bool
224
    {
225 8
        $source = $this->getSourceNodeInfo();
226 8
        $target = $this->getTargetNodeInfo();
227
228 8
        return ($target->getLeft() > $source->getLeft() && $target->getRight() < $source->getRight()) ? true : false;
229
    }
230
231
    /**
232
     * @return AdapterInterface
233
     */
234 12
    protected function getAdapter(): AdapterInterface
235
    {
236 12
        return $this->adapter;
237
    }
238
239
    /**
240
     * @return NodeInfo
241
     */
242 8
    protected function getSourceNodeInfo(): NodeInfo
243
    {
244 8
        return $this->sourceNodeInfo;
245
    }
246
247
    /**
248
     * @param NodeInfo $sourceNodeInfo
249
     */
250 9
    private function setSourceNodeInfo(NodeInfo $sourceNodeInfo): void
251
    {
252 9
        $this->sourceNodeInfo = $sourceNodeInfo;
253 9
    }
254
255
    /**
256
     * @return NodeInfo
257
     */
258 8
    protected function getTargetNodeInfo(): NodeInfo
259
    {
260 8
        return $this->targetNodeInfo;
261
    }
262
263
    /**
264
     * @param NodeInfo $targetNodeInfo
265
     */
266 9
    private function setTargetNodeInfo(NodeInfo $targetNodeInfo): void
267
    {
268 9
        $this->targetNodeInfo = $targetNodeInfo;
269 9
    }
270
}
271