Test Failed
Push — master ( 61197e...5bf490 )
by Terzi
04:50
created

ValidatesForm::makeRequiredRule()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 0
cts 1
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Terranet\Administrator\Traits\Module;
4
5
use Doctrine\DBAL\Schema\Column;
6
use Illuminate\Validation\Rule;
0 ignored issues
show
Bug introduced by
The type Illuminate\Validation\Rule was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Terranet\Administrator\Architect;
8
use Terranet\Rankable\Rankable;
0 ignored issues
show
Bug introduced by
The type Terranet\Rankable\Rankable was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use function admin\db\scheme;
10
11
trait ValidatesForm
12
{
13
    /**
14
     * Define validation rules.
15
     */
16
    public function rules()
17
    {
18
        return $this->scaffoldRules();
19
    }
20
21
    /**
22
     * Build a list of supposed validators based on columns and indexes information.
23
     *
24
     * @return array
25
     */
26
    protected function scaffoldRules()
27
    {
28
        $rules = [];
29
30
        $eloquent = $this->model();
0 ignored issues
show
Bug introduced by
It seems like model() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

30
        /** @scrutinizer ignore-call */ 
31
        $eloquent = $this->model();
Loading history...
31
        $table = $eloquent->getTable();
32
33
        foreach (scheme()->columns($table) as $column) {
34
            $name = $column->getName();
35
            // skip Primary Key
36
            if ($name === $eloquent->getKeyName()) {
37
                continue;
38
            }
39
40
            // skip rankable field
41
            if ($eloquent instanceof Rankable && $name === $eloquent->getRankableColumn()) {
42
                continue;
43
            }
44
45
            if (!empty($columnRules = $this->proposeColumnRules($eloquent, $column))) {
46
                $rules[$name] = implode('|', $columnRules);
47
            }
48
        }
49
50
        return $rules;
51
    }
52
53
    /**
54
     * Build a list of validators for a column.
55
     *
56
     * @param        $eloquent
57
     * @param  Column  $column
58
     * @return array
59
     */
60
    protected function proposeColumnRules($eloquent, Column $column)
61
    {
62
        $rules = [];
63
64
        if ('password' === $column->getName()) {
65
            return ['nullable', 'min:6'];
66
        }
67
68
        if ((($this->fillable($column->getName(), $eloquent) || $this->isForeignKey($column, $eloquent))
69
            && $column->getNotnull())) {
70
            // make required rule first
71
            array_unshift($rules, 'required');
72
        }
73
74
        if ($this->isUnique($column, $eloquent)) {
75
            $rules[] = 'unique';
76
        }
77
78
        if ('BooleanType' === ($classname = class_basename($column->getType()))) {
79
            $rules[] = 'numeric';
80
            $rules[] = 'boolean';
81
82
            if (app()->runningUnitTests()) {
0 ignored issues
show
Bug introduced by
The function app was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

82
            if (/** @scrutinizer ignore-call */ app()->runningUnitTests()) {
Loading history...
83
                $rules = array_diff($rules, ['required']);
84
            }
85
        }
86
87
        if (\in_array($classname, ['IntegerType', 'DecimalType'], true)) {
88
            $rules[] = 'numeric';
89
90
            if (false === $column->getNotnull()) {
91
                $rules[] = 'nullable';
92
            }
93
94
            if ($column->getUnsigned()) {
95
                $rules[] = 'unsigned';
96
            }
97
        }
98
99
        if ($this->isForeignKey($column, $eloquent)) {
100
            $rules[] = 'foreign';
101
        }
102
103
        return array_map(function ($rule) use ($column, $eloquent) {
104
            $method = 'make'.ucfirst($rule).'Rule';
105
106
            return \call_user_func_array([$this, $method], [$column, $eloquent]);
107
        }, $rules);
108
    }
109
110
    /**
111
     * Check if column fillable.
112
     *
113
     * @param            $column
114
     * @param            $eloquent
115
     * @return bool
116
     */
117
    protected function fillable($column, $eloquent)
118
    {
119
        return \in_array($column, $eloquent->getFillable(), true);
120
    }
121
122
    /**
123
     * Check if column is a part of foreign keys.
124
     *
125
     * @param $column
126
     * @param $eloquent
127
     * @return bool
128
     */
129
    protected function isForeignKey($column, $eloquent)
130
    {
131
        foreach ($foreign = scheme()->foreignKeys($eloquent->getTable()) as $foreign) {
0 ignored issues
show
Unused Code introduced by
The assignment to $foreign is dead and can be removed.
Loading history...
132
            if (\in_array($column->getName(), $foreign->getLocalColumns(), true)) {
133
                return $foreign;
134
            }
135
        }
136
137
        return false;
138
    }
139
140
    /**
141
     * @param  Column  $column
142
     * @param        $eloquent
143
     * @return array
144
     */
145
    protected function isUnique(Column $column, $eloquent)
146
    {
147
        foreach (scheme()->indexes($eloquent->getTable()) as $indexName => $index) {
148
            if (\in_array($column->getName(), $index->getColumns(), true) && $index->isUnique()) {
149
                return true;
150
            }
151
        }
152
153
        return false;
154
    }
155
156
    /**
157
     * Make required rule.
158
     *
159
     * @param  Column  $column
160
     * @param        $eloquent
161
     * @return string
162
     */
163
    protected function makeRequiredRule(Column $column, $eloquent)
164
    {
165
        return 'required';
166
    }
167
168
    /**
169
     * Make numeric rule.
170
     *
171
     * @param  Column  $column
172
     * @param        $eloquent
173
     * @return array
174
     */
175
    protected function makeNumericRule(Column $column, $eloquent)
176
    {
177
        return $column->getScale() ? 'numeric' : 'integer';
178
    }
179
180
    /**
181
     * Make unsigned rule.
182
     *
183
     * @param  Column  $column
184
     * @param        $eloquent
185
     * @return array
186
     */
187
    protected function makeUnsignedRule(Column $column, $eloquent)
188
    {
189
        return 'min:0';
190
    }
191
192
    /**
193
     * @param  Column  $column
194
     * @param $eloquent
195
     * @return Rule
196
     * @throws \ReflectionException
197
     */
198
    protected function makeBooleanRule(Column $column, $eloquent)
199
    {
200
        $values = [0, 1];
201
        if (Architect::castedEnumType($eloquent, $column->getName())) {
202
            $values = array_keys(Architect::castedEnumValues($eloquent, $column->getName()));
203
        }
204
205
        return Rule::in($values);
206
    }
207
208
    /**
209
     * Parse foreign keys for column presence.
210
     *
211
     * @param  Column  $column
212
     * @param        $eloquent
213
     * @return array
214
     */
215
    protected function makeForeignRule(Column $column, $eloquent)
216
    {
217
        $foreign = $this->isForeignKey($column, $eloquent);
218
        $foreignTable = $foreign->getForeignTableName();
219
        $foreignKey = head($foreign->getForeignColumns());
220
221
        return "exists:{$foreignTable},{$foreignKey}";
222
    }
223
224
    /**
225
     * @param $column
226
     * @param $eloquent
227
     * @return string
228
     */
229
    protected function makeUniqueRule($column, $eloquent)
230
    {
231
        if (\is_object($key = $this->routeParam('id')) && method_exists($key, 'getKey')) {
232
            $key = $key->getKey();
233
        }
234
235
        return "unique:{$eloquent->getTable()},{$column->getName()}".($key ? ",{$key}" : '');
236
    }
237
238
    /**
239
     * @param $column
240
     * @param $eloquent
241
     * @return string
242
     */
243
    protected function makeNullableRule($column, $eloquent)
244
    {
245
        return 'nullable';
246
    }
247
248
    /**
249
     * @param $name
250
     * @param  null  $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
251
     * @return mixed
252
     */
253
    protected function routeParam($name, $default = null)
254
    {
255
        return \Route::current()->parameter($name, $default);
256
    }
257
}
258