Validable   B
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 319
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 319
rs 8.2857
c 0
b 0
f 0
wmc 39
lcom 2
cbo 3

21 Methods

Rating   Name   Duplication   Size   Complexity  
A bootValidable() 0 10 4
A isValid() 0 6 1
A skipValidation() 0 4 1
A disableValidation() 0 6 2
A enableValidation() 0 6 1
A skipsValidation() 0 4 1
A validationEnabled() 0 4 1
A getValidationErrors() 0 4 1
A getMessageBag() 0 4 1
A getInvalidAttributes() 0 4 1
A getValidator() 0 13 2
A getValidationMessages() 0 6 2
A getValidationAttributes() 0 6 2
A getCreateRules() 0 8 2
C gatherRules() 0 35 7
A getUpdateRules() 0 4 2
A getUpdateRulesForId() 0 4 1
A getValidatedFields() 0 10 2
A getRulesGroups() 0 12 3
A getRulesGroup() 0 4 1
A setValidatorFactory() 0 4 1
1
<?php
2
3
namespace Sofa\Eloquence;
4
5
use Sofa\Eloquence\Validable\Observer;
6
use Illuminate\Contracts\Validation\Factory;
7
8
/**
9
 * @method integer getKey()
10
 * @method string getKeyName()
11
 */
12
trait Validable
13
{
14
    /**
15
     * Validation switch.
16
     *
17
     * @var boolean
18
     */
19
    protected $skipValidation = false;
20
21
    /**
22
     * Validator instance.
23
     *
24
     * @var \Illuminate\Contracts\Validation\Validator
25
     */
26
    protected $validator;
27
28
    /**
29
     * Validator factory instance.
30
     *
31
     * @var \Illuminate\Contracts\Validation\Factory
32
     */
33
    protected static $validatorFactory;
34
35
    /**
36
     * All the validation rules for this model.
37
     *
38
     * @var array
39
     */
40
    protected static $rulesMerged;
41
42
    /**
43
     * Register hooks for the trait.
44
     *
45
     * @codeCoverageIgnore
46
     *
47
     * @return void
48
     */
49
    public static function bootValidable()
50
    {
51
        static::observe(new Observer);
52
53
        if (!static::$validatorFactory) {
54
            if (function_exists('app') && app()->bound('validator')) {
55
                static::setValidatorFactory(app('validator'));
56
            }
57
        }
58
    }
59
60
    /**
61
     * Determine whether all the attributes on this instance pass validation.
62
     *
63
     * @return boolean
64
     */
65
    public function isValid()
66
    {
67
        $this->getValidator()->setData($this->getAttributes());
0 ignored issues
show
Bug introduced by
It seems like getAttributes() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Bug introduced by
The method setData() does not seem to exist on object<Illuminate\Contracts\Validation\Validator>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
68
69
        return $this->getValidator()->passes();
0 ignored issues
show
Bug introduced by
The method passes() does not seem to exist on object<Illuminate\Contracts\Validation\Validator>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
70
    }
71
72
    /**
73
     * Skip validation on the next saving attempt.
74
     *
75
     * @return $this
76
     */
77
    public function skipValidation()
78
    {
79
        return $this->disableValidation($once = true);
80
    }
81
82
    /**
83
     * Disable validation for this instance.
84
     *
85
     * @return $this
86
     */
87
    public function disableValidation($once = false)
88
    {
89
        $this->skipValidation = ($once) ? Observer::SKIP_ONCE : Observer::SKIP_ALWAYS;
90
91
        return $this;
92
    }
93
94
    /**
95
     * Enable validation for this instance.
96
     *
97
     * @return $this
98
     */
99
    public function enableValidation()
100
    {
101
        $this->skipValidation = false;
102
103
        return $this;
104
    }
105
106
    /**
107
     * Get current validation flag.
108
     *
109
     * @return integer|false
110
     */
111
    public function skipsValidation()
112
    {
113
        return $this->skipValidation;
114
    }
115
116
    /**
117
     * Determine whether validation is enabled for this instance.
118
     *
119
     * @return boolean
120
     */
121
    public function validationEnabled()
122
    {
123
        return !$this->skipsValidation();
124
    }
125
126
    /**
127
     * Retrieve validation error messages.
128
     *
129
     * @return \Illuminate\Support\MessageBag
130
     */
131
    public function getValidationErrors()
132
    {
133
        return $this->getMessageBag();
134
    }
135
136
    /**
137
     * Retrieve validation error messages.
138
     *
139
     * @return \Illuminate\Support\MessageBag
140
     */
141
    public function getMessageBag()
142
    {
143
        return $this->getValidator()->getMessageBag();
144
    }
145
146
    /**
147
     * Get names of the attributes that didn't pass validation.
148
     *
149
     * @return array
150
     */
151
    public function getInvalidAttributes()
152
    {
153
        return array_keys($this->getValidationErrors()->toArray());
154
    }
155
156
    /**
157
     * Get the validator instance.
158
     *
159
     * @return \Illuminate\Contracts\Validation\Validator
160
     */
161
    public function getValidator()
162
    {
163
        if (!$this->validator) {
164
            $this->validator = static::$validatorFactory->make(
165
                [],
166
                static::getCreateRules(),
167
                static::getValidationMessages(),
168
                static::getValidationAttributes()
169
            );
170
        }
171
172
        return $this->validator;
173
    }
174
175
    /**
176
     * Get custom validation messages.
177
     *
178
     * @return array
179
     */
180
    public static function getValidationMessages()
181
    {
182
        return (property_exists(get_called_class(), 'validationMessages'))
183
            ? static::$validationMessages
184
            : [];
185
    }
186
187
    /**
188
     * Get custom validation attribute names.
189
     *
190
     * @return array
191
     */
192
    public static function getValidationAttributes()
193
    {
194
        return (property_exists(get_called_class(), 'validationAttributes'))
195
            ? static::$validationAttributes
196
            : [];
197
    }
198
199
    /**
200
     * Get all the validation rules for this model.
201
     *
202
     * @return array
203
     */
204
    public static function getCreateRules()
205
    {
206
        if (!static::$rulesMerged) {
207
            static::$rulesMerged = static::gatherRules();
208
        }
209
210
        return static::$rulesMerged;
211
    }
212
213
    /**
214
     * Gather all the rules for the model and store it for easier use.
215
     *
216
     * @return array
217
     */
218
    protected static function gatherRules()
219
    {
220
        // This rather gnarly looking logic is just for developer convenience
221
        // so he can define multiple rule groups on the model for clarity
222
        // and now we simply gather all rules and merge them together.
223
        $keys = static::getValidatedFields();
224
225
        $result = array_fill_keys($keys, []);
226
227
        foreach ($keys as $key) {
228
            foreach (static::getRulesGroups() as $groupName) {
229
                $group = static::getRulesGroup($groupName);
230
231
                if (isset($group[$key])) {
232
                    $rules = is_array($group[$key])
233
                            ? $group[$key]
234
                            : explode('|', $group[$key]);
235
236
                    foreach ($rules as &$rule) {
237
                        if ($rule === 'unique') {
238
                            $table = (new static)->getTable();
0 ignored issues
show
Bug introduced by
It seems like getTable() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
239
240
                            $rule .= ":{$table}";
241
                        }
242
                    }
243
244
                    unset($rule);
245
246
                    $result[$key] = array_unique(array_merge($result[$key], $rules));
247
                }
248
            }
249
        }
250
251
        return $result;
252
    }
253
254
    /**
255
     * Get all validation rules for update on this model.
256
     *
257
     * @return array
258
     */
259
    public function getUpdateRules()
260
    {
261
        return ($this->getKey()) ? static::getUpdateRulesForId($this) : static::getCreateRules();
262
    }
263
264
    /**
265
     * Get all validation rules for update for given id.
266
     *
267
     * @param  \Illuminate\Database\Eloquent\Model|integer|string $id
268
     * @return array
269
     */
270
    public static function getUpdateRulesForId($id)
271
    {
272
        return rules_for_update(static::getCreateRules(), $id, (new static)->getKeyName());
273
    }
274
275
    /**
276
     * Get array of attributes that have validation rules defined.
277
     *
278
     * @return array
279
     */
280
    public static function getValidatedFields()
281
    {
282
        $fields = [];
283
284
        foreach (static::getRulesGroups() as $groupName) {
285
            $fields = array_merge($fields, array_keys(static::getRulesGroup($groupName)));
286
        }
287
288
        return array_values(array_unique($fields));
289
    }
290
291
    /**
292
     * Get all the rules groups defined on this model.
293
     *
294
     * @return array
295
     */
296
    protected static function getRulesGroups()
297
    {
298
        $groups = [];
299
300
        foreach (get_class_vars(get_called_class()) as $property => $val) {
301
            if (preg_match('/^.*rules$/i', $property)) {
302
                $groups[] = $property;
303
            }
304
        }
305
306
        return $groups;
307
    }
308
309
    /**
310
     * Get rules from given group.
311
     *
312
     * @param  string $group
313
     * @return array
314
     */
315
    protected static function getRulesGroup($group)
316
    {
317
        return static::$$group;
318
    }
319
320
    /**
321
     * Set validation factory instance for this model.
322
     *
323
     * @param  \Illuminate\Contracts\Validation\Factory
324
     * @return void
325
     */
326
    public static function setValidatorFactory(Factory $factory)
327
    {
328
        static::$validatorFactory = $factory;
329
    }
330
}
331