Completed
Push — develop ( c8e703...0b876c )
by Freddie
03:17
created

SchemaAttribute::min()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of FlexPHP.
4
 *
5
 * (c) Freddie Gar <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace FlexPHP\Schema;
11
12
use FlexPHP\Schema\Constants\Keyword;
13
use FlexPHP\Schema\Constants\Rule;
14
use FlexPHP\Schema\Validations\SchemaAttributeLogicValidation;
15
use FlexPHP\Schema\Validations\SchemaAttributeValidation;
16
17
final class SchemaAttribute implements SchemaAttributeInterface
18
{
19
    /**
20
     * @var string
21
     */
22
    private $name;
23
24
    /**
25
     * @var string
26
     */
27
    private $dataType;
28
29
    /**
30
     * @var array<string, mixed>
31
     */
32
    private $constraints = [];
33
34
    /**
35
     * @param mixed $constraints
36
     */
37 116
    public function __construct(string $name, string $dataType, $constraints = null)
38
    {
39 116
        $this->setName($name);
40 116
        $this->setDataType($dataType);
41 116
        $this->setConstraints($constraints);
42
43 116
        $this->validate();
44 84
    }
45
46 116
    public function name(): string
47
    {
48 116
        return $this->name;
49
    }
50
51 116
    public function dataType(): string
52
    {
53 116
        return $this->dataType;
54
    }
55
56 116
    public function constraints(): array
57
    {
58 116
        return $this->constraints;
59
    }
60
61 6
    public function type(): ?string
62
    {
63 6
        return $this->constraints[Rule::TYPE] ?? null;
64
    }
65
66 29
    public function isRequired(): bool
67
    {
68 29
        return (bool)($this->constraints[Rule::REQUIRED] ?? false);
69
    }
70
71 64
    public function minLength(): ?int
72
    {
73 64
        return $this->constraints[Rule::MINLENGTH] ?? null;
74
    }
75
76 59
    public function maxLength(): ?int
77
    {
78 59
        return $this->constraints[Rule::MAXLENGTH] ?? null;
79
    }
80
81 24
    public function minCheck(): ?int
82
    {
83 24
        return $this->constraints[Rule::MINCHECK] ?? null;
84
    }
85
86 23
    public function maxCheck(): ?int
87
    {
88 23
        return $this->constraints[Rule::MAXCHECK] ?? null;
89
    }
90
91 55
    public function min(): ?int
92
    {
93 55
        return $this->constraints[Rule::MIN] ?? null;
94
    }
95
96 53
    public function max(): ?int
97
    {
98 53
        return $this->constraints[Rule::MAX] ?? null;
99
    }
100
101 6
    public function equalTo(): ?string
102
    {
103 6
        return $this->constraints[Rule::EQUALTO] ?? null;
104
    }
105
106 97
    public function isPk(): bool
107
    {
108 97
        return (bool)($this->constraints[Rule::PRIMARYKEY] ?? false);
109
    }
110
111 94
    public function isAi(): bool
112
    {
113 94
        return (bool)($this->constraints[Rule::AUTOINCREMENT] ?? false);
114
    }
115
116 21
    public function isFk(): bool
117
    {
118 21
        return (bool)($this->constraints[Rule::FOREIGNKEY] ?? false);
119
    }
120
121 9
    public function fkTable(): ?string
122
    {
123 9
        return $this->constraints[Rule::FOREIGNKEY]['table'] ?? null;
124
    }
125
126 9
    public function fkId(): ?string
127
    {
128 9
        return $this->constraints[Rule::FOREIGNKEY]['id'] ?? null;
129
    }
130
131 9
    public function fkName(): ?string
132
    {
133 9
        return $this->constraints[Rule::FOREIGNKEY]['name'] ?? null;
134
    }
135
136 90
    public function isCa(): bool
137
    {
138 90
        return (bool)($this->constraints[Rule::CREATEDAT] ?? false);
139
    }
140
141 89
    public function isUa(): bool
142
    {
143 89
        return (bool)($this->constraints[Rule::UPDATEDAT] ?? false);
144
    }
145
146 90
    public function isBlame(): bool
147
    {
148 90
        return $this->isCa() || $this->isUa();
149
    }
150
151 116
    public function properties(): array
152
    {
153
        return [
154 116
            Keyword::NAME => $this->name(),
155 116
            Keyword::DATATYPE => $this->dataType(),
156 116
            Keyword::CONSTRAINTS => $this->constraints(),
157
        ];
158
    }
159
160 78
    public function typeHint(): string
161
    {
162
        $typeHintByDataType = [
163 78
            'smallint' => 'int',
164
            'integer' => 'int',
165
            'float' => 'float',
166
            'double' => 'float',
167
            'bool' => 'bool',
168
            'boolean' => 'bool',
169
            'date' => '\DateTime',
170
            'date_immutable' => '\DateTimeImmutable',
171
            'datetime' => '\DateTime',
172
            'datetime_immutable' => '\DateTimeImmutable',
173
            'datetimetz' => '\DateTime',
174
            'datetimetz_immutable' => '\DateTimeImmutable',
175
            'time' => '\DateTime',
176
            'time_immutable' => '\DateTimeImmutable',
177
            'array' => 'array',
178
            'simple_array' => 'array',
179
            'json_array' => 'array',
180
        ];
181
182 78
        if (isset($typeHintByDataType[$this->dataType()])) {
183 47
            return $typeHintByDataType[$this->dataType()];
184
        }
185
186 35
        return 'string';
187
    }
188
189 116
    private function validate(): void
190
    {
191 116
        (new SchemaAttributeValidation($this->properties()))->validate();
192 113
        (new SchemaAttributeLogicValidation($this))->validate();
193 84
    }
194
195 116
    private function setName(string $name): void
196
    {
197 116
        $this->name = $name;
198 116
    }
199
200 116
    private function setDataType(string $dataType): void
201
    {
202 116
        $this->dataType = $dataType;
203 116
    }
204
205
    /**
206
     * @param mixed $constraints
207
     */
208 116
    private function setConstraints($constraints): void
209
    {
210 116
        if (!empty($constraints)) {
211 96
            if (\is_string($constraints)) {
212 61
                $this->setConstraintsFromString($constraints);
213
            } else {
214 35
                $this->setConstraintsFromArray($constraints);
215
            }
216
        }
217 116
    }
218
219 61
    private function setConstraintsFromString(string $constraints): void
220
    {
221 61
        $this->setConstraintsFromArray($this->getConstraintsFromString($constraints));
222 61
    }
223
224 96
    private function setConstraintsFromArray(array $constraints): void
225
    {
226 96
        $this->constraints = $this->getConstraintsCast($constraints);
227 96
    }
228
229 61
    private function getConstraintsFromString(string $constraints): array
230
    {
231 61
        $_constraints = \explode('|', $constraints);
232
233
        /** @var mixed $_constraint */
234 61
        foreach ($_constraints as $index => $_constraint) {
235 61
            $_rule = \explode(':', $_constraint);
236
237 61
            if (\count($_rule) === 2) {
238 49
                [$_name, $_options] = $_rule;
239
240 49
                if (Rule::FOREIGNKEY !== $_name && \strpos($_options, ',') !== false) { // Range
241 2
                    [$min, $max] = \explode(',', $_options);
242 2
                    $_options = \compact('min', 'max');
243 47
                } elseif (\preg_match('/^false$/i', $_options)) { // False as string
244 9
                    $_options = false;
245 41
                } elseif (\preg_match('/^true$/i', $_options)) { // True as string
246 9
                    $_options = true;
247
                }
248
249 49
                $_constraints[$_name] = $_options;
250
            } else {
251 23
                $_constraints[$_rule[0]] = true;
252
            }
253
254 61
            unset($_constraints[$index]);
255
        }
256
257 61
        return $_constraints;
258
    }
259
260 96
    private function getConstraintsCast(array $constraints): array
261
    {
262 96
        foreach ($constraints as $name => $value) {
263 96
            if (\is_int($name)) {
264 10
                $constraints[$value] = true;
265 10
                unset($constraints[$name]);
266 91
            } elseif ($name === Rule::CHECK || $name === Rule::LENGTH) {
267 4
                $constraints['min' . $name] = (int)$value['min'];
268 4
                $constraints['max' . $name] = (int)$value['max'];
269 4
                unset($constraints[$name]);
270 87
            } elseif ($name === Rule::FOREIGNKEY && \is_string($value)) {
271 10
                $constraints[$name] = $this->getFkOptions($value);
272
            } else {
273 96
                $constraints[$name] = \is_numeric($value) ? (int)$value : $value;
274
            }
275
        }
276
277 96
        return $constraints;
278
    }
279
280 10
    private function getFkOptions(string $constraint): array
281
    {
282 10
        $_vars = \explode(',', $constraint);
283 10
        $fkName = 'name';
284 10
        $fkId = 'id';
285
286 10
        switch (\count($_vars)) {
287 10
            case 3:
288 2
                [$fkTable, $fkName, $fkId] = $_vars;
289
290 2
                break;
291 8
            case 2:
292 4
                [$fkTable, $fkName] = $_vars;
293
294 4
                break;
295
            default:
296 4
                [$fkTable] = $_vars;
297
298 4
                break;
299
        }
300
301
        return [
302 10
            'table' => $fkTable,
303 10
            'name' => $fkName,
304 10
            'id' => $fkId,
305
        ];
306
    }
307
}
308