Completed
Push — master ( 43d7fb...779a1c )
by Dmitry
03:34
created

Schema   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 4

Importance

Changes 0
Metric Value
wmc 55
lcom 3
cbo 4
dl 0
loc 213
rs 6.8
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
B createSpace() 0 32 6
C getDefaultValue() 0 22 12
C formatValue() 0 27 13
B getSpace() 0 18 5
A getSpaceId() 0 7 2
A getSpaces() 0 7 2
A hasSpace() 0 4 1
A once() 0 10 2
A reset() 0 13 1
A getMeta() 0 13 2
A setMeta() 0 6 1
A toUnderscore() 0 12 4
A toCamelCase() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like Schema often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Schema, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Tarantool\Mapper;
4
5
use Exception;
6
7
class Schema
8
{
9
    private $mapper;
10
11
    private $names = [];
12
    private $spaces = [];
13
    private $params = [];
14
15
    public function __construct(Mapper $mapper, $meta = null)
16
    {
17
        $this->mapper = $mapper;
18
        if ($meta) {
19
            $this->setMeta($meta);
20
        } else {
21
            $this->reset();
22
        }
23
    }
24
25
    public function createSpace($space, $config = [])
26
    {
27
        $engine = 'memtx';
28
        if (array_key_exists('properties', $config)) {
29
            if (array_key_exists('engine', $config)) {
30
                $engine = $config['engine'];
31
                if (!in_array($engine, ['memtx', 'vinyl'])) {
32
                    throw new Exception("Invalid engine $engine");
33
                }
34
            }
35
        }
36
37
        $id = $this->mapper->getClient()->evaluate("
38
            box.schema.space.create('$space', {
39
                engine = '$engine'
40
            })
41
            return box.space.$space.id
42
        ")->getData()[0];
43
44
        $this->names[$space] = $id;
45
        $this->engines[$space] = $engine;
0 ignored issues
show
Bug introduced by
The property engines does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
46
47
        $this->spaces[$id] = new Space($this->mapper, $id, $space, $engine);
48
49
        $properties = array_key_exists('properties', $config) ? $config['properties'] : $config;
50
51
        if ($properties) {
52
            $this->spaces[$id]->addProperties($properties);
53
        }
54
55
        return $this->spaces[$id];
56
    }
57
58
    public function getDefaultValue($type)
59
    {
60
        switch ($type) {
61
            case 'STR':
62
            case 'STRING':
63
            case 'str':
64
            case 'string':
65
                return (string) null;
66
67
            case 'double':
68
            case 'float':
69
            case 'number':
70
                return (float) null;
71
72
            case 'unsigned':
73
            case 'UNSIGNED':
74
            case 'num':
75
            case 'NUM':
76
                return (int) null;
77
        }
78
        throw new Exception("Invalid type $type");
79
    }
80
81
    public function formatValue($type, $value)
82
    {
83
        if (is_null($value)) {
84
            return null;
85
        }
86
        switch ($type) {
87
            case 'STR':
88
            case 'STRING':
89
            case 'str':
90
            case 'string':
91
                return (string) $value;
92
93
            case 'double':
94
            case 'float':
95
            case 'number':
96
                return (float) $value;
97
98
            case 'unsigned':
99
            case 'UNSIGNED':
100
            case 'num':
101
            case 'NUM':
102
                return (int) $value;
103
104
            default:
105
                return $value;
106
        }
107
    }
108
109
    public function getSpace($id)
110
    {
111
        if (is_string($id)) {
112
            return $this->getSpace($this->getSpaceId($id));
113
        }
114
115
        if (!$id) {
116
            throw new Exception("Space id or name not defined");
117
        }
118
119
        if (!array_key_exists($id, $this->spaces)) {
120
            $name = array_search($id, $this->names);
121
            $meta = array_key_exists($id, $this->params) ? $this->params[$id] : null;
122
            $engine = $this->engines[$name];
123
            $this->spaces[$id] = new Space($this->mapper, $id, $name, $engine, $meta);
124
        }
125
        return $this->spaces[$id];
126
    }
127
128
    public function getSpaceId($name)
129
    {
130
        if (!$this->hasSpace($name)) {
131
            throw new Exception("No space $name");
132
        }
133
        return $this->names[$name];
134
    }
135
136
    public function getSpaces()
137
    {
138
        foreach ($this->names as $id) {
139
            $this->getSpace($id);
140
        }
141
        return $this->spaces;
142
    }
143
144
    public function hasSpace($name)
145
    {
146
        return array_key_exists($name, $this->names);
147
    }
148
149
    public function once($name, $callback)
150
    {
151
        $key = 'mapper-once' . $name;
152
153
        $rows = $this->mapper->find('_schema', ['key' => $key]);
154
        if (!count($rows)) {
155
            $this->mapper->create('_schema', ['key' => $key]);
156
            return $callback($this->mapper);
157
        }
158
    }
159
160
    public function reset()
161
    {
162
        [$this->names, $this->engines] = $this->mapper->getClient()->evaluate("
163
            local spaces = {}
164
            local engines = {}
165
            local i, s
166
            for i, s in box.space._vspace:pairs() do
167
                spaces[s[3]] = s[1]
168
                engines[s[3]] = s[4]
169
            end
170
            return spaces, engines
171
        ")->getData();
172
    }
173
174
    public function getMeta()
175
    {
176
        $params = [];
177
        foreach ($this->getSpaces() as $space) {
178
            $params[$space->getId()] = $space->getMeta();
179
        }
180
181
        return [
182
            'engines' => $this->engines,
183
            'names' => $this->names,
184
            'params' => $params,
185
        ];
186
    }
187
188
    public function setMeta($meta)
189
    {
190
        $this->engines = $meta['engines'];
191
        $this->names = $meta['names'];
192
        $this->params = $meta['params'];
193
    }
194
195
    private $underscores = [];
196
197
    public function toUnderscore($input)
198
    {
199
        if (!array_key_exists($input, $this->underscores)) {
200
            preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
201
            $ret = $matches[0];
202
            foreach ($ret as &$match) {
203
                $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
204
            }
205
            $this->underscores[$input] = implode('_', $ret);
206
        }
207
        return $this->underscores[$input];
208
    }
209
210
    private $camelcase = [];
211
212
    public function toCamelCase($input)
213
    {
214
        if (!array_key_exists($input, $this->camelcase)) {
215
            $this->camelcase[$input] = lcfirst(implode('', array_map('ucfirst', explode('_', $input))));
216
        }
217
        return $this->camelcase[$input];
218
    }
219
}
220