Completed
Push — master ( 8fe865 )
by Dmitry
04:10
created

Space::isSpecial()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 0
1
<?php
2
3
namespace Tarantool\Mapper;
4
5
use Exception;
6
7
class Space
8
{
9
    private $mapper;
10
    
11
    private $id;
12
    private $name;
13
    private $format;
14
    private $indexes;
15
16
    private $formatNamesHash = [];
17
    private $formatTypesHash = [];
18
19
    private $repository;
20
21
    public function __construct(Mapper $mapper, $id, $name)
22
    {
23
        $this->mapper = $mapper;
24
        $this->id = $id;
25
        $this->name = $name;
26
    }
27
28
    public function addProperty($name, $type)
29
    {
30
        $format = $this->getFormat();
31
        foreach($format as $field) {
32
            if($field['name'] == $name) {
33
                throw new Exception("Property $name exists");
34
            }
35
        }
36
        $format[] = compact('name', 'type');
37
        $this->format = $format;
38
        $this->mapper->getClient()->evaluate("box.space[$this->id]:format(...)", [$format]);
39
40
        $this->parseFormat();
41
    }
42
43
    public function removeProperty($name)
44
    {
45
        $format = $this->getFormat();
46
        $last = array_pop($format);
47
        if($last['name'] != $name) {
48
            throw new Exception("Remove only last property");
49
        }
50
        $this->mapper->getClient()->evaluate("box.space[$this->id]:format(...)", [$format]);
51
        $this->format = $format;
52
53
        $this->parseFormat();
54
    }
55
56
    public function removeIndex($name)
57
    {
58
        $this->mapper->getClient()->evaluate("box.space[$this->id].index.$name:drop()");
59
        $this->indexes = [];
60
        $this->mapper->getRepository('_index')->flushCache();
61
    }
62
63
    public function createIndex($config)
64
    {
65
66
        if(!is_array($config)) {
67
            $config = ['fields' => $config];
68
        }
69
        
70
71
        if(!array_key_exists('fields', $config)) {
72
            if(array_values($config) != $config) {
73
                throw new Exception("Invalid index configuration");
74
            }
75
            $config = [
76
                'fields' => $config
77
            ];
78
        }
79
80
        if(!is_array($config['fields'])) {
81
            $config['fields'] = [$config['fields']];
82
        }
83
84
        $options = [
85
            'parts' => []
86
        ];
87
88
        foreach($config as $k => $v) {
89
            if($k != 'name' && $k != 'fields') {
90
                $options[$k] = $v;
91
            }
92
        }
93
94
        foreach($config['fields'] as $property) {
95
            if(!$this->getPropertyType($property)) {
96
                throw new Exception("Unknown property $property", 1);
97
            }
98
            $options['parts'][] = $this->getPropertyIndex($property)+1;
99
            $options['parts'][] = $this->getPropertyType($property);
100
        }
101
102
        $name = array_key_exists('name', $config) ? $config['name'] : implode('_', $config['fields']);
103
104
        $this->mapper->getClient()->evaluate("box.space[$this->id]:create_index('$name', ...)", [$options]);
105
        $this->indexes = [];
106
107
    }
108
109
    public function isSpecial()
110
    {
111
        return $this->id == 280 || $this->id == 288;
112
    }
113
114
    public function getId()
115
    {
116
        return $this->id;
117
    }
118
119
    public function getFormat()
120
    {
121
        if(!$this->format) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->format of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
122
            if($this->isSpecial()) {
123
                $this->format = $this->mapper->getClient()
124
                    ->getSpace(280)->select([$this->id])->getData()[0][6];
125
126
            } else {
127
                $this->format = $this->mapper->findOne('_space', ['id' => $this->id])->format;
128
            }
129
            if(!$this->format) {
130
                $this->format = [];
131
            }
132
            $this->parseFormat();
133
        }
134
135
        return $this->format;
136
    }
137
138
    public function getMapper()
139
    {
140
        return $this->mapper;
141
    }
142
143
    public function getName()
144
    {
145
        return $this->name;
146
    }
147
148
    private function parseFormat()
149
    {
150
        $this->formatTypesHash = [];
151
        $this->formatNamesHash = [];
152
        foreach($this->format as $key => $row) {
153
            $this->formatTypesHash[$row['name']] = $row['type'];
154
            $this->formatNamesHash[$row['name']] = $key;
155
        }
156
    }
157
158
    public function hasProperty($name)
159
    {
160
        $this->getFormat();
161
        return array_key_exists($name, $this->formatNamesHash);
162
    }
163
164
    public function getPropertyType($name)
165
    {
166
        if(!$this->hasProperty($name)) {
167
            throw new Exception("No property $name");
168
        }
169
        return $this->formatTypesHash[$name];
170
    }
171
172
    public function getPropertyIndex($name)
173
    {
174
        if(!$this->hasProperty($name)) {
175
            throw new Exception("No property $name");
176
        }
177
        return $this->formatNamesHash[$name];
178
    }
179
180
    public function getIndexes()
181
    {
182
        if(!$this->indexes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->indexes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
183
            if($this->isSpecial()) {
184
                $this->indexes = [];
185
                $indexTuples = $this->mapper->getClient()->getSpace(288)->select([$this->id])->getData();
186
                $indexFormat = $this->mapper->getSchema()->getSpace(288)->getFormat();
187
                foreach($indexTuples as $tuple) {
188
                    $instance = (object) [];
189
                    foreach($indexFormat as $index => $format) {
190
                        $instance->{$format['name']} = $tuple[$index];
191
                    }
192
                    $this->indexes[] = $instance;
193
                }
194
195
            } else {
196
                $this->indexes = $this->mapper->find('_index', ['id' => $this->id]);
197
            }
198
        }
199
        return $this->indexes;
200
    }
201
202
    public function castIndex($params)
203
    {
204
        $keys = array_keys($params);
0 ignored issues
show
Unused Code introduced by
$keys 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...
205
206
        $keys = [];
207
        foreach($params as $name => $value) {
208
            $keys[] = $this->getPropertyIndex($name);
209
        }
210
        if($keys == [0]) {
211
            // primary index
212
            return 0;
213
        }
214
215
        // equals
216
        foreach($this->getIndexes() as $index) {
217
            $equals = false;
218
            if(count($keys) == count($index->parts)) {
219
                // same length
220
                $equals = true;
221
                foreach($index->parts as $part) {
222
                    $equals = $equals && in_array($part[0], $keys);
223
                }
224
            }
225
            
226
            if($equals) {
227
                return $index->iid;
228
            }
229
        }
230
231
        // index part
232
        foreach($this->getIndexes() as $index) {
233
            $partial = [];
234
            foreach($index->parts as $n => $part) {
235
                if(!array_key_exists($n, $keys)) {
236
                    break;
237
                }
238
                if($keys[$n] != $part[0]) {
239
                    break;
240
                }
241
                $partial[] = $keys[$n];
242
            }
243
244
            if(count($partial) == count($keys)) {
245
                return $index->iid;
246
            }
247
        }
248
249
        throw new Exception("No index");
250
    }
251
252
    public function getIndexValues($indexId, $params)
253
    {
254
        $index = $this->getIndexes()[$indexId];
255
        $format = $this->getFormat();
256
257
        $values = [];
258
        foreach($index->parts as $part) {
259
            $name = $format[$part[0]]['name'];
260
            if(!array_key_exists($name, $params)) {
261
                break;
262
            }
263
            $values[] = $this->mapper->getSchema()->formatValue($part[1], $params[$name]);
264
        }
265
        return $values;
266
    }
267
268
    public function getPrimaryIndex()
269
    {
270
        $indexes = $this->getIndexes();
271
        if(!count($indexes)) {
272
            throw new Exception("No primary index");
273
        }
274
        return $indexes[0];
275
    }
276
277
    public function getTupleKey($tuple)
278
    {
279
        $key = [];
280
        foreach($this->getPrimaryIndex()->parts as $part) {
281
            $key[] = $tuple[$part[0]];
282
        }
283
        return count($key) == 1 ? $key[0] : implode(':', $key);
284
    }
285
286
    public function getInstanceKey($instance)
287
    {
288
289
        $key = [];
290
291
        foreach($this->getPrimaryIndex()->parts as $part) {
292
            $name = $this->getFormat()[$part[0]]['name'];
293
            if(!property_exists($instance, $name)) {
294
                throw new Exception("Field $name is undefined", 1);
295
            }
296
            $key[] = $instance->$name;
297
        }
298
299
        return count($key) == 1 ? $key[0] : implode(':', $key);
300
    }
301
302
    public function getRepository()
303
    {
304
        $class = Repository::class;
305
        foreach($this->mapper->getPlugins() as $plugin) {
306
            $repositoryClass = $plugin->getRepositoryClass($this);
307
            if($repositoryClass) {
308
                if($class != Repository::class) {
309
                    throw new Exception('Repository class override');
310
                }
311
                $class = $repositoryClass;
312
            }
313
        }
314
        return $this->repository ?: $this->repository = new $class($this);
315
    }
316
}