Test Failed
Push — develop ( eeff2c...6435cb )
by Freddie
05:45
created

SchemaAttributeLogicValidation::hasCheck()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
nc 2
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 6
rs 10
c 1
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 134
        Action::CREATE,
23
        Action::READ,
24 134
        Action::UPDATE,
25 134
        Action::DELETE,
26
    ];
27 134
28
    /**
29 134
     * @var SchemaAttributeInterface
30 21
     */
31
    private $property;
32
33 115
    public function __construct(SchemaAttributeInterface $property)
34
    {
35 115
        $this->property = $property;
36 20
    }
37 3
38
    public function validate(): void
39
    {
40 17
        if (empty($this->property->constraints())) {
41 2
            return;
42
        }
43
44 15
        $name = 'Logic: [' . $this->property->name() . '] ';
45 1
46
        if ($this->property->isPk()) {
47
            if (!$this->property->isRequired()) {
48 14
                throw new InvalidSchemaAttributeException($name . 'Primary Key must be required.');
49 1
            }
50
51
            if ($this->property->isFk()) {
52
                throw new InvalidSchemaAttributeException($name . 'Primary Key cannot be Foreing Key too.');
53 108
            }
54 10
55 1
            if ($this->isInt() && !$this->property->isAi()) {
56
                throw new InvalidSchemaAttributeException($name . 'Primary Key numeric not autoincrement.');
57
            }
58 9
59 1
            if ($this->property->isAi() && $this->hasSizingConstraint()) {
60
                throw new InvalidSchemaAttributeException($name . 'Primary Key autoincrement cannot has sizing.');
61
            }
62
        }
63 106
64 2
        if ($this->property->isAi()) {
65
            if (!$this->property->isPk()) {
66
                throw new InvalidSchemaAttributeException($name . 'Autoincrement must be Primary Key too.');
67 104
            }
68 1
69
            if (!$this->isInt()) {
70
                throw new InvalidSchemaAttributeException($name . 'Autoincrement must be numeric.');
71 103
            }
72 4
        }
73
74
        if ($this->property->isBlameAt() && !$this->isDate()) {
75 99
            throw new InvalidSchemaAttributeException($name . 'Blame At property must be date datatype.');
76 1
        }
77
78
        if ($this->property->isCa() && $this->property->isUa()) {
79 98
            throw new InvalidSchemaAttributeException($name . 'Created and Updated At in same property is not valid.');
80 10
        }
81
82
        if ($this->property->isBlameBy() && !$this->isInt()) {
83 88
            throw new InvalidSchemaAttributeException($name . 'Blame By property must be integer datatype.');
84 4
        }
85
86
        if ($this->property->isCb() && $this->property->isUb()) {
87 84
            throw new InvalidSchemaAttributeException($name . 'Created and Updated By in same property is not valid.');
88 4
        }
89
90 80
        if ($this->isNumeric() && $this->hasLength()) {
91
            throw new InvalidSchemaAttributeException($name . 'Numeric properties use: min, max.');
92 28
        }
93
94 28
        if ($this->isString() && $this->hasSize()) {
95
            throw new InvalidSchemaAttributeException($name . 'String properties use: minlength, maxlength.');
96
        }
97 87
98
        if (($this->isDate() || $this->isBinary()) && $this->hasSizingConstraint()) {
99 87
            throw new InvalidSchemaAttributeException($name . 'Date, bool, blob properties not use min, max, etc');
100
        }
101
102 98
        if ($this->hasFormat()) {
103
            if ($this->isString()) {
104 98
                throw new InvalidSchemaAttributeException(\sprintf(
105
                    '%sString properties not allow format',
106
                    $name
107 88
                ));
108
            }
109 88
110
            if ($this->isBinary()) {
111
                throw new InvalidSchemaAttributeException(\sprintf(
112 68
                    '%sBinary (bool, blob) properties not allow format',
113
                    $name
114 68
                ));
115
            }
116
117 70
            if ($this->isArray()) {
118
                throw new InvalidSchemaAttributeException(\sprintf(
119 70
                    '%sArray (array, simple_array, json) properties not allow format',
120
                    $name
121
                ));
122 58
            }
123
124 58
            if ($this->isNumeric() && !$this->property->isFormat(Format::MONEY)) {
125
                throw new InvalidSchemaAttributeException(\sprintf(
126
                    '%sNumeric properties not allow format: %s',
127 24
                    $name,
128
                    $this->property->format()
129 24
                ));
130
            }
131
132 27
            if ($this->isDate() && $this->property->isFormat(Format::MONEY)) {
133
                throw new InvalidSchemaAttributeException(\sprintf(
134 27
                    '%sDate property not allow format: %s',
135
                    $name,
136
                    $this->property->format()
137
                ));
138
            }
139
        }
140
141
        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...
142
            throw new InvalidSchemaAttributeException(\sprintf(
143
                '%sOnly property with Foreing Key allow fchars option',
144
                $name,
145
            ));
146
        }
147
148
        if ($this->property->fkcheck() && !$this->property->isFk()) {
149
            throw new InvalidSchemaAttributeException(\sprintf(
150
                '%sOnly property with Foreing Key allow fkcheck option',
151
                $name,
152
            ));
153
        }
154
155
        if ($this->property->usedInAll() && \count($this->property->show()) > 1) {
156
            throw new InvalidSchemaAttributeException(\sprintf(
157
                '%sShow constraint miss-configuration: ALL (a) option is exclusive',
158
                $name,
159
            ));
160
        }
161
162
        if ($this->property->usedInAll() && \count($this->property->hide()) > 1) {
163
            throw new InvalidSchemaAttributeException(\sprintf(
164
                '%sHide constraint miss-configuration: ALL (a) option is exclusive',
165
                $name,
166
            ));
167
        }
168
169
        foreach (self::ACTIONS as $action) {
170
            if (\in_array($action, $this->property->show()) && \in_array($action, $this->property->hide())) {
171
                throw new InvalidSchemaAttributeException(\sprintf(
172
                    '%sShow/Hide constraint miss-configuration: (' . $action . ') option is present in both',
173
                    $name,
174
                ));
175
            }
176
        }
177
    }
178
179
    private function isInt(): bool
180
    {
181
        return \in_array($this->property->dataType(), ['smallint', 'integer', 'bigint']);
182
    }
183
184
    private function isDate(): bool
185
    {
186
        return \strpos($this->property->typeHint(), '\Date') !== false;
187
    }
188
189
    private function isArray(): bool
190
    {
191
        return \in_array($this->property->dataType(), ['array', 'simple_array', 'json']);
192
    }
193
194
    private function isNumeric(): bool
195
    {
196
        return \in_array($this->property->dataType(), ['smallint', 'integer', 'bigint', 'double', 'float']);
197
    }
198
199
    private function isString(): bool
200
    {
201
        return $this->property->dataType() !== 'bigint' && $this->property->typeHint() === 'string';
202
    }
203
204
    private function isBinary(): bool
205
    {
206
        return \in_array($this->property->dataType(), ['bool', 'boolean', 'blob']);
207
    }
208
209
    private function hasLength(): bool
210
    {
211
        return $this->property->minLength() !== null || $this->property->maxLength() !== null;
212
    }
213
214
    private function hasSize(): bool
215
    {
216
        return $this->property->min() !== null || $this->property->max() !== null;
217
    }
218
219
    private function hasCheck(): bool
220
    {
221
        return $this->property->minCheck() !== null || $this->property->maxCheck() !== null;
222
    }
223
224
    private function hasSizingConstraint(): bool
225
    {
226
        return $this->hasSize() || $this->hasLength() || $this->hasCheck();
227
    }
228
229
    private function hasFormat(): bool
230
    {
231
        return (bool)$this->property->format();
232
    }
233
}
234