Completed
Push — master ( b30b9b...187882 )
by Dmitry
04:07 queued 01:47
created

NestedSet::beforeCreate()   B

Complexity

Conditions 9
Paths 19

Size

Total Lines 56
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 56
rs 7.1584
c 0
b 0
f 0
cc 9
eloc 33
nc 19
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', 'root', '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
            ['root', 'left'],
29
            ['root', '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 beforeCreate(Entity $entity, Space $space)
41
    {
42
        if ($this->isNested($space)) {
43
            $repository = $space->getRepository();
44
45
            if ($entity->parent) {
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
                $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...
48
49
                $updateLeft = [];
50
                $updateRight = [];
51
                foreach ($repository->find(['root' => $entity->root]) as $node) {
0 ignored issues
show
Bug introduced by
The property root 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...
52
                    if ($node->right >= $parent->right) {
53
                        if ($node->left > $parent->right) {
54
                            $updateLeft[$node->left] = $node;
55
                        }
56
                        $updateRight[$node->right] = $node;
57
                    }
58
                }
59
60
                $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...
61
                $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...
62
63
                krsort($updateRight);
64
                foreach ($updateRight as $node) {
65
                    $node->right += 2;
66
                    $node->save();
67
                }
68
69
                krsort($updateLeft);
70
                foreach ($updateLeft as $node) {
71
                    $node->left += 2;
72
                    $node->save();
73
                }
74
            } else {
75
                // new root
76
                $map = $space->getTupleMap();
77
78
                $entity->root = $entity->root ?: 0;
79
                $max = $this->mapper->getClient()->evaluate("
80
                    local max = 0
81
                    local root = $entity->root
82
                    for i, n in box.space.tree.index.root_right:pairs(root, {iterator = 'le'}) do
83
                        if n[$map->root] == root then
84
                            max = n[$map->right]
85
                        end
86
                        break
87
                    end
88
                    return max
89
                ")->getData()[0];
90
91
                $entity->left = $max + 1;
92
                $entity->right = $entity->left + 1;
93
            }
94
        }
95
    }
96
97
    public function beforeRemove(Entity $instance, Space $space)
98
    {
99
        $spaceName = $space->getName();
100
        $map = $space->getTupleMap();
101
102
        $result = $this->mapper->getClient()->evaluate("
103
            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...
104
            local remove_list = {}
105
            local update_list = {}
106
            for i, current in box.space.$spaceName.index.root_left:pairs({removed_node[$map->root], removed_node[$map->left]}, 'gt') do
107
                if current[$map->root] ~= removed_node[$map->root] then
108
                    break
109
                end
110
                if current[$map->left] < removed_node[$map->right] then
111
                    table.insert(remove_list, current[$map->id])
112
                else
113
                    table.insert(update_list, current[$map->id])
114
                end
115
            end
116
117
            local delta = removed_node[$map->right] - removed_node[$map->left] + 1
118
119
            for i, id in ipairs(remove_list) do
120
                box.space.$spaceName:delete(id)
121
            end
122
123
            box.space.$spaceName:update($instance->id, {
124
                {'=', $map->left, 0},
125
                {'=', $map->right, 0},
126
            })
127
128
            for i, id in pairs(update_list) do
129
                box.space.$spaceName:update(id, {
130
                    {'-', $map->left, delta},
131
                    {'-', $map->right, delta}
132
                })
133
            end
134
135
            return remove_list, update_list, delta, removed_node
136
        ")->getData();
137
138
        // remove
139
        foreach ($result[0] as $id) {
140
            $space->getRepository()->forget($id);
141
        }
142
143
        // update
144
        foreach ($result[1] as $id) {
145
            $space->getRepository()->sync($id);
146
        }
147
148
        $space->getRepository()->flushCache();
149
    }
150
151
    public function isNested(Space $space, $force = false)
152
    {
153
        $spaceName = $space->getName();
154
        if ($force || !array_key_exists($spaceName, $this->nestedSpaces)) {
155
            $fields = [];
156
            foreach ($space->getFormat() as $field) {
157
                $fields[] = $field['name'];
158
            }
159
160
            $this->nestedSpaces[$spaceName] = !count(array_diff($this->keys, $fields));
161
        }
162
163
        return $this->nestedSpaces[$spaceName];
164
    }
165
166
    public function resetNestedSpacesCache()
167
    {
168
        $this->nestedSpaces = [];
169
    }
170
}
171