Completed
Push — master ( fce112...cb5961 )
by Dmitry
01:38
created

Schema::toCamelCase()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Tarantool\Mapper;
6
7
use Closure;
8
use Exception;
9
use Tarantool\Client\Schema\Criteria;
10
use Tarantool\Client\Schema\Space as ClientSpace;
11
12
class Schema
13
{
14
    private $mapper;
15
16
    private $names = [];
17
    private $spaces = [];
18
    private $params = [];
19
    private $engines = [];
20
21
    public function __construct(Mapper $mapper, $meta = null)
22
    {
23
        $this->mapper = $mapper;
24
        if ($meta) {
25
            $this->setMeta($meta);
26
        } else {
27
            $this->reset();
28
        }
29
    }
30
31
    public function createSpace(string $space, array $config = []) : Space
32
    {
33
        $engine = 'memtx';
34
        if (array_key_exists('properties', $config)) {
35
            if (array_key_exists('engine', $config)) {
36
                $engine = $config['engine'];
37
                if (!in_array($engine, ['memtx', 'vinyl'])) {
38
                    throw new Exception("Invalid engine $engine");
39
                }
40
            }
41
        }
42
43
        [$id] = $this->mapper->getClient()->evaluate("
0 ignored issues
show
Bug introduced by
The variable $id does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

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