Completed
Push — master ( 8a13a1...5138b1 )
by Dmitry
02:21
created

NestedSet::beforeRemove()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 57
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 57
rs 9.0309
c 0
b 0
f 0
cc 4
eloc 26
nc 5
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Tarantool\Mapper\Plugin;
4
5
use Tarantool\Mapper\Entity;
6
use Tarantool\Mapper\Mapper;
7
use Tarantool\Mapper\Plugin;
8
use Tarantool\Mapper\Space;
9
10
class NestedSet extends Plugin
11
{
12
    private $keys = ['id', 'parent', 'group', 'depth', 'left', 'right'];
13
    private $nestedSpaces = [];
14
15
    public function __construct(Mapper $mapper)
16
    {
17
        $this->mapper = $mapper;
18
    }
19
20
    public function addIndexes(Space $space)
21
    {
22
        $indexes = [
23
            ['id'],
24
            [
25
                'fields' => ['parent'],
26
                'unique' => false,
27
            ],
28
            ['group', 'left'],
29
            ['group', 'right'],
30
        ];
31
32
        foreach ($indexes as $index) {
33
            $fields = array_key_exists('fields', $index) ? $index['fields'] : $index;
34
            if ($space->castIndex(array_flip($fields), true) === null) {
35
                $space->createIndex($index);
36
            }
37
        }
38
    }
39
40
    public function beforeUpdate(Entity $entity, Space $space)
41
    {
42
        if ($this->isNested($space)) {
43
            $repository = $space->getRepository();
44
            $spaceName = $space->getName();
0 ignored issues
show
Unused Code introduced by
$spaceName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
45
46
            $parent = $repository->findOne($entity->parent);
0 ignored issues
show
Bug introduced by
The property parent does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
47
48
            $client = $this->mapper->getClient();
0 ignored issues
show
Unused Code introduced by
$client is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
49
            $map = $space->getTupleMap();
50
51
            $old_entity = $repository->getOriginal($entity);
52
53
            foreach (['group'] as $field) {
54
                if ($old_entity[$map->$field-1] != $entity->$field) {
55
                    throw new \Exception(ucfirst($field)." can't be changed");
56
                }
57
            }
58
59
            if ($old_entity[$map->parent-1] != $entity->parent) {
60
                $leftValue = $entity->left;
0 ignored issues
show
Bug introduced by
The property left does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
61
                $rightValue = $entity->right;
0 ignored issues
show
Bug introduced by
The property right does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
62
                $toRoot = $entity->parent == 0 ? 1 : 0;
63
64
                $value = 0;
65
                $delta = 0;
66
                $depth = 0;
67
                if ($entity->parent) {
68
                    $value = $parent->right;
69
                    $depth = $parent->depth - $entity->depth + 1;
0 ignored issues
show
Bug introduced by
The property depth does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
70
                    $delta = $rightValue - $leftValue + 1;
71
                }
72
73
                $right_key_near = 0;
74
                if (!$entity->parent) {
75
                    foreach ($repository->find(['group' => $entity->group]) as $node) {
0 ignored issues
show
Bug introduced by
The property group does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
76
                        if (!$node->parent && $node->right > $right_key_near) {
77
                            $right_key_near = $node->right;
78
                        }
79
                    }
80
                }
81
                $skew_tree = $rightValue - $leftValue + 1;
82
                $skew_edit = $right_key_near - $leftValue + 1;
83
84
                $spaceName = $space->getName();
85
86
                if ($rightValue < $right_key_near) {
87
                    $skew_edit -= $skew_tree;
88
                }
89
90
                $result = $this->mapper->getClient()->evaluate("
91
                    local result = {}
92
                    local updates = {}
93
                    local maxRightTuple = box.space.$spaceName.index.group_right:max(right);
94
                    local maxLeftTuple = box.space.$spaceName.index.group_left:max(left);
95
                    local maxValue = 100
96
                    if maxRightTuple ~= nil then
97
                        maxValue = maxValue + maxRightTuple[$map->right]
98
                    end
99
                    if maxLeftTuple ~= nil then
100
                        maxValue = maxValue + maxLeftTuple[$map->left]
101
                    end
102
103
                    local leftValue = $entity->left
104
                    local rightValue = $entity->right
105
106
                    if $leftValue >= $value then
107
                        leftValue = leftValue + ($delta)
108
                        rightValue = rightValue + ($delta)
109
                    end
110
                    local left
111
                    local right
112
113
                    box.begin()
114
                    for i, node in box.space.$spaceName.index.group_right:pairs({{$entity->group}, 1}, 'ge') do
115
                        if node[$map->group] ~= $entity->group then
116
                            break
117
                        end
118
                        left = node[$map->left]
119
                        right = node[$map->right]
120
                        if $toRoot == 1 then
121
                            if left >= $leftValue and right <= $rightValue then
122
                                if node[$map->id] ~= $entity->id then
0 ignored issues
show
Bug introduced by
The property id does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
123
                                    table.insert(updates, {node[$map->id], $map->left, left + 1 - $leftValue})
124
                                    table.insert(updates, {node[$map->id], $map->right, right + 1 - $leftValue})
125
                                else
126
                                    table.insert(updates, {node[$map->id], $map->right, right + $skew_edit})
127
                                    table.insert(updates, {node[$map->id], $map->left, left + $skew_edit})
128
                                end
129
                                table.insert(updates, {node[$map->id], $map->depth, node[$map->depth] - $entity->depth})
130
                            end
131
                            if left >= $rightValue + 1 then
132
                                table.insert(updates, {node[$map->id], $map->left, left + $leftValue - $rightValue - 1})
133
                            end
134
                            if right >= $rightValue + 1 then
135
                                table.insert(updates, {node[$map->id], $map->right, right + $leftValue - $rightValue - 1})
136
                            end
137
                        else
138
                            if left >= $value then
139
                                left = left + ($delta)
140
                                table.insert(updates, {node[$map->id], $map->left, left})
141
                            end
142
                            if right >= $value then
143
                                right = right + ($delta)
144
                                table.insert(updates, {node[$map->id], $map->right, right})
145
                            end
146
147
                            if left >= leftValue and right <= rightValue then
148
                                table.insert(updates, {node[$map->id], $map->depth, node[$map->depth] + $depth})
149
                            end
150
151
                            if left >= leftValue and left <= rightValue then
152
                                left = left + $value - leftValue
153
                                table.insert(updates, {node[$map->id], $map->left, left})
154
                            end
155
                            if right >= leftValue and right <= rightValue then
156
                                right = right + $value - leftValue
157
                                table.insert(updates, {node[$map->id], $map->right, right})
158
                            end
159
                            if left >= rightValue + 1 then
160
                                left = left-($delta)
161
                                table.insert(updates, {node[$map->id], $map->left, left})
162
                            end
163
                            if right >= rightValue + 1 then
164
                                right = right-($delta)
165
                                table.insert(updates, {node[$map->id], $map->right, right})
166
                            end
167
                        end
168
                    end
169
                    for i, node in pairs(updates) do
170
                        box.space.$spaceName:update(node[1], {{'=', node[2], maxValue}})
171
                        maxValue = maxValue + 1
172
                    end
173
                    for i, node in pairs(updates) do
174
                        table.insert(result, node[1])
175
                        box.space.$spaceName:update(node[1], {{'=', node[2], node[3]}})
176
                    end
177
                    box.commit()
178
179
                    return result
180
                ")->getData();
181
182
                foreach (array_unique($result[0]) as $id) {
183
                    $space->getRepository()->sync($id, ['left', 'right', 'depth']);
184
                }
185
186
                $space->getRepository()->flushCache();
187
            }
188
        }
189
    }
190
191
    public function beforeCreate(Entity $entity, Space $space)
192
    {
193
        if (!$this->isNested($space)) {
194
            return;
195
        }
196
        $repository = $space->getRepository();
197
198
        if ($entity->parent) {
199
            $parent = $repository->findOne($entity->parent);
0 ignored issues
show
Bug introduced by
The property parent does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
200
            $entity->depth = $parent->depth + 1;
0 ignored issues
show
Bug introduced by
The property depth does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
201
202
            $updateLeft = [];
203
            $updateRight = [];
204
            foreach ($repository->find(['group' => $entity->group]) as $node) {
0 ignored issues
show
Bug introduced by
The property group does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
205
                if ($node->right >= $parent->right) {
206
                    if ($node->left > $parent->right) {
207
                        $updateLeft[$node->left] = $node;
208
                    }
209
                    $updateRight[$node->right] = $node;
210
                }
211
            }
212
213
            $entity->left = $parent->right;
0 ignored issues
show
Bug introduced by
The property left does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
214
            $entity->right = $entity->left + 1;
0 ignored issues
show
Bug introduced by
The property right does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
215
216
            krsort($updateRight);
217
            foreach ($updateRight as $node) {
218
                $node->right += 2;
219
                $node->save();
220
            }
221
222
            krsort($updateLeft);
223
            foreach ($updateLeft as $node) {
224
                $node->left += 2;
225
                $node->save();
226
            }
227
        } else {
228
            // new group
229
            $map = $space->getTupleMap();
230
            $spaceName = $space->getName();
231
232
            $entity->group = $entity->group ?: 0;
233
            $max = $this->mapper->getClient()->evaluate("
234
                local max = 0
235
                local group = $entity->group
236
                for i, n in box.space.$spaceName.index.group_right:pairs(group, {iterator = 'le'}) do
237
                    if n[$map->group] == group then
238
                        max = n[$map->right]
239
                    end
240
                    break
241
                end
242
                return max
243
            ")->getData()[0];
244
245
            $entity->left = $max + 1;
246
            $entity->right = $entity->left + 1;
247
        }
248
    }
249
250
    public function beforeRemove(Entity $instance, Space $space)
251
    {
252
        if (!$this->isNested($space)) {
253
            return;
254
        }
255
256
        $spaceName = $space->getName();
257
        $map = $space->getTupleMap();
258
259
        $result = $this->mapper->getClient()->evaluate("
260
            local removed_node = box.space.$spaceName:get($instance->id)
0 ignored issues
show
Bug introduced by
The property id does not seem to exist in Tarantool\Mapper\Entity.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
261
            local remove_list = {}
262
            local update_list = {}
263
            for i, current in box.space.$spaceName.index.group_left:pairs({removed_node[$map->group], removed_node[$map->left]}, 'gt') do
264
                if current[$map->group] ~= removed_node[$map->group] then
265
                    break
266
                end
267
                if current[$map->left] < removed_node[$map->right] then
268
                    table.insert(remove_list, current[$map->id])
269
                else
270
                    table.insert(update_list, current[$map->id])
271
                end
272
            end
273
274
            local delta = removed_node[$map->right] - removed_node[$map->left] + 1
275
276
            for i, id in ipairs(remove_list) do
277
                box.space.$spaceName:delete(id)
278
            end
279
280
            box.space.$spaceName:update($instance->id, {
281
                {'=', $map->left, 0},
282
                {'=', $map->right, 0},
283
            })
284
285
            for i, id in pairs(update_list) do
286
                box.space.$spaceName:update(id, {
287
                    {'-', $map->left, delta},
288
                    {'-', $map->right, delta}
289
                })
290
            end
291
292
            return remove_list, update_list, delta, removed_node
293
        ")->getData();
294
295
        // remove
296
        foreach ($result[0] as $id) {
297
            $space->getRepository()->forget($id);
298
        }
299
300
        // update
301
        foreach ($result[1] as $id) {
302
            $space->getRepository()->sync($id);
303
        }
304
305
        $space->getRepository()->flushCache();
306
    }
307
308
    public function isNested(Space $space, $force = false)
309
    {
310
        $spaceName = $space->getName();
311
        if ($force || !array_key_exists($spaceName, $this->nestedSpaces)) {
312
            $fields = [];
313
            foreach ($space->getFormat() as $field) {
314
                $fields[] = $field['name'];
315
            }
316
317
            $this->nestedSpaces[$spaceName] = !count(array_diff($this->keys, $fields));
318
        }
319
320
        return $this->nestedSpaces[$spaceName];
321
    }
322
323
    public function resetNestedSpacesCache()
324
    {
325
        $this->nestedSpaces = [];
326
    }
327
}
328