Passed
Push — develop ( 8d04e4...f8d7bf )
by Freddie
03:08
created

SchemaAttributeLogicValidation::isText()   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\Validations;
11
12
use FlexPHP\Schema\Constants\Action;
13
use FlexPHP\Schema\Constants\Format;
14
use FlexPHP\Schema\Exception\InvalidSchemaAttributeException;
15
use FlexPHP\Schema\SchemaAttributeInterface;
16
17
class SchemaAttributeLogicValidation implements ValidationInterface
18
{
19
    private const ACTIONS = [
20
        Action::ALL,
21
        Action::INDEX,
22
        Action::CREATE,
23
        Action::READ,
24
        Action::UPDATE,
25
        Action::DELETE,
26
    ];
27
28
    private \FlexPHP\Schema\SchemaAttributeInterface $property;
29
30 278
    public function __construct(SchemaAttributeInterface $property)
31
    {
32 278
        $this->property = $property;
33 278
    }
34
35 278
    public function validate(): void
36
    {
37 278
        if (empty($this->property->constraints())) {
38 39
            return;
39
        }
40
41 250
        $name = 'Logic: [' . $this->property->name() . '] ';
42
43 250
        if ($this->property->isPk()) {
44 29
            if (!$this->property->isRequired()) {
45 3
                throw new InvalidSchemaAttributeException($name . 'Primary Key must be required.');
46
            }
47
48 26
            if ($this->property->isFk()) {
49 2
                throw new InvalidSchemaAttributeException($name . 'Primary Key cannot be Foreing Key too.');
50
            }
51
52 24
            if ($this->isInt() && !$this->property->isAi()) {
53 1
                throw new InvalidSchemaAttributeException($name . 'Primary Key numeric not autoincrement.');
54
            }
55
56 23
            if ($this->property->isAi() && $this->hasSizingConstraint()) {
57 1
                throw new InvalidSchemaAttributeException($name . 'Primary Key autoincrement cannot has sizing.');
58
            }
59
        }
60
61 243
        if ($this->property->isAi()) {
62 19
            if (!$this->property->isPk()) {
63 1
                throw new InvalidSchemaAttributeException($name . 'Autoincrement must be Primary Key too.');
64
            }
65
66 18
            if (!$this->isInt()) {
67 1
                throw new InvalidSchemaAttributeException($name . 'Autoincrement must be numeric.');
68
            }
69
        }
70
71 241
        if ($this->property->isBlameAt() && !$this->isDate()) {
72 2
            throw new InvalidSchemaAttributeException($name . 'Blame At property must be date datatype.');
73
        }
74
75 239
        if ($this->property->isCa() && $this->property->isUa()) {
76 1
            throw new InvalidSchemaAttributeException($name . 'Created and Updated At in same property is not valid.');
77
        }
78
79 238
        if ($this->property->isBlameBy() && !$this->isInt()) {
80 4
            throw new InvalidSchemaAttributeException($name . 'Blame By property must be integer datatype.');
81
        }
82
83 234
        if ($this->property->isCb() && $this->property->isUb()) {
84 1
            throw new InvalidSchemaAttributeException($name . 'Created and Updated By in same property is not valid.');
85
        }
86
87 233
        if ($this->isNumeric() && $this->hasLength()) {
88 10
            throw new InvalidSchemaAttributeException($name . 'Numeric properties use: min, max.');
89
        }
90
91 223
        if ($this->isString() && $this->hasSize()) {
92 4
            throw new InvalidSchemaAttributeException($name . 'String properties use: minlength, maxlength.');
93
        }
94
95 219
        if (($this->isDate() || $this->isBinary()) && $this->hasSizingConstraint()) {
96 4
            throw new InvalidSchemaAttributeException($name . 'Date, bool, blob properties not use min, max, etc');
97
        }
98
99 215
        if ($this->hasFormat()) {
100 35
            if ($this->isString()) {
101 7
                throw new InvalidSchemaAttributeException(\sprintf(
102 7
                    '%sString properties not allow format',
103 7
                    $name
104
                ));
105
            }
106
107 28
            if ($this->isText()) {
108
                throw new InvalidSchemaAttributeException(\sprintf(
109
                    '%sText properties not allow default',
110
                    $name
111
                ));
112
            }
113
114 28
            if ($this->isObject()) {
115
                throw new InvalidSchemaAttributeException(\sprintf(
116
                    '%sObject properties not allow format',
117
                    $name
118
                ));
119
            }
120
121 28
            if ($this->isBinary()) {
122 6
                throw new InvalidSchemaAttributeException(\sprintf(
123 6
                    '%sBinary (binary, bool, blob) properties not allow format',
124 6
                    $name
125
                ));
126
            }
127
128 22
            if ($this->isArray()) {
129 9
                throw new InvalidSchemaAttributeException(\sprintf(
130 9
                    '%sArray (array, simple_array, json) properties not allow format',
131 9
                    $name
132
                ));
133
            }
134
135 13
            if ($this->isNumeric() && !$this->property->isFormat(Format::MONEY)) {
136 4
                throw new InvalidSchemaAttributeException(\sprintf(
137 4
                    '%sNumeric properties not allow format: %s',
138 4
                    $name,
139 4
                    $this->property->format()
140
                ));
141
            }
142
143 9
            if ($this->isDate() && $this->property->isFormat(Format::MONEY)) {
144 6
                throw new InvalidSchemaAttributeException(\sprintf(
145 6
                    '%sDate property not allow format: %s',
146 6
                    $name,
147 6
                    $this->property->format()
148
                ));
149
            }
150
        }
151
152 183
        if ($this->property->fchars() && !$this->property->isFk()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->property->fchars() of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
153 5
            throw new InvalidSchemaAttributeException(\sprintf(
154 5
                '%sOnly property with Foreing Key allow fchars option',
155 5
                $name,
156
            ));
157
        }
158
159 178
        if ($this->property->fkcheck() && !$this->property->isFk()) {
160 1
            throw new InvalidSchemaAttributeException(\sprintf(
161 1
                '%sOnly property with Foreing Key allow fkcheck option',
162 1
                $name,
163
            ));
164
        }
165
166 177
        if ($this->property->usedInAll() && \count($this->property->show()) > 1) {
167
            throw new InvalidSchemaAttributeException(\sprintf(
168
                '%sShow constraint miss-configuration: ALL (a) option is exclusive',
169
                $name,
170
            ));
171
        }
172
173 177
        if ($this->property->usedInAll() && \count($this->property->hide()) > 1) {
174
            throw new InvalidSchemaAttributeException(\sprintf(
175
                '%sHide constraint miss-configuration: ALL (a) option is exclusive',
176
                $name,
177
            ));
178
        }
179
180 177
        foreach (self::ACTIONS as $action) {
181 177
            if (\in_array($action, $this->property->show()) && \in_array($action, $this->property->hide())) {
182 6
                throw new InvalidSchemaAttributeException(\sprintf(
183 6
                    '%sShow/Hide constraint miss-configuration: (' . $action . ') option is present in both',
184 6
                    $name,
185
                ));
186
            }
187
        }
188
189 171
        if (($default = $this->property->default()) !== null) {
190 19
            if ($this->isString() && \is_bool($default)) {
191 2
                throw new InvalidSchemaAttributeException(\sprintf(
192 2
                    '%sString properties not allow default: NOW or boolean, used string or int values',
193 2
                    $name
194
                ));
195
            }
196
197 17
            if ($this->isText()) {
198 1
                throw new InvalidSchemaAttributeException(\sprintf(
199 1
                    '%sText properties not allow default',
200 1
                    $name
201
                ));
202
            }
203
204 16
            if ($this->isObject()) {
205 1
                throw new InvalidSchemaAttributeException(\sprintf(
206 1
                    '%sObject properties not allow default',
207 1
                    $name
208
                ));
209
            }
210
211 15
            if ($this->isBinary()) {
212 2
                throw new InvalidSchemaAttributeException(\sprintf(
213 2
                    '%sBinary (bool, blob) properties not allow default',
214 2
                    $name
215
                ));
216
            }
217
218 13
            if ($this->isArray()) {
219 3
                throw new InvalidSchemaAttributeException(\sprintf(
220 3
                    '%sArray (array, simple_array, json) properties not allow default',
221 3
                    $name
222
                ));
223
            }
224
225 10
            if ($this->isNumeric() && !\is_numeric($default)) {
226 2
                throw new InvalidSchemaAttributeException(\sprintf(
227 2
                    '%sNumeric properties not allow default: %s, use numeric values',
228 2
                    $name,
229 2
                    $default
230
                ));
231
            }
232
233 8
            if ($this->isDate() && $default !== 'NOW') {
234 2
                throw new InvalidSchemaAttributeException(\sprintf(
235 2
                    '%sDate property not allow default: %s, use null or "NOW" string',
236 2
                    $name,
237 2
                    $default
238
                ));
239
            }
240
        }
241 158
    }
242
243 49
    private function isInt(): bool
244
    {
245 49
        return \in_array($this->property->dataType(), ['smallint', 'integer', 'bigint']);
246
    }
247
248 222
    private function isDate(): bool
249
    {
250 222
        return \strpos($this->property->typeHint(), '\Date') !== false;
251
    }
252
253 35
    private function isArray(): bool
254
    {
255 35
        return \in_array($this->property->dataType(), ['array', 'simple_array', 'json']);
256
    }
257
258 233
    private function isNumeric(): bool
259
    {
260 233
        return \in_array($this->property->dataType(), ['smallint', 'integer', 'bigint', 'double', 'float']);
261
    }
262
263 45
    private function isText(): bool
264
    {
265 45
        return $this->property->dataType() === 'text';
266
    }
267
268 44
    private function isObject(): bool
269
    {
270 44
        return $this->property->dataType() === 'object';
271
    }
272
273 223
    private function isString(): bool
274
    {
275 223
        return $this->property->dataType() !== 'bigint' && $this->property->typeHint() === 'string';
276
    }
277
278 190
    private function isBinary(): bool
279
    {
280 190
        return \in_array($this->property->dataType(), ['binary', 'bool', 'boolean', 'blob']);
281
    }
282
283 140
    private function hasLength(): bool
284
    {
285 140
        return $this->property->minLength() !== null || $this->property->maxLength() !== null;
286
    }
287
288 155
    private function hasSize(): bool
289
    {
290 155
        return $this->property->min() !== null || $this->property->max() !== null;
291
    }
292
293 69
    private function hasCheck(): bool
294
    {
295 69
        return $this->property->minCheck() !== null || $this->property->maxCheck() !== null;
296
    }
297
298 72
    private function hasSizingConstraint(): bool
299
    {
300 72
        return $this->hasSize() || $this->hasLength() || $this->hasCheck();
301
    }
302
303 215
    private function hasFormat(): bool
304
    {
305 215
        return (bool)$this->property->format();
306
    }
307
}
308