Passed
Push — master ( ece31d...41b8a6 )
by Paul
10:20 queued 04:17
created

Validator::addFailure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use BadMethodCallException;
6
use GeminiLabs\SiteReviews\Defaults\ValidationStringsDefaults;
7
use GeminiLabs\SiteReviews\Helper;
8
use GeminiLabs\SiteReviews\Modules\Validator\ValidationRules;
9
10
/**
11
 * @see \Illuminate\Validation\Validator (5.3)
12
 */
13
class Validator
14
{
15
    use ValidationRules;
16
17
    /**
18
     * @var array
19
     */
20
    public $errors = [];
21
22
    /**
23
     * The data under validation.
24
     * @var array
25
     */
26
    protected $data = [];
27
28
    /**
29
     * The failed validation rules.
30
     * @var array
31
     */
32
    protected $failedRules = [];
33
34
    /**
35
     * The rules to be applied to the data.
36
     * @var array
37
     */
38
    protected $rules = [];
39
40
    /**
41
     * The size related validation rules.
42
     * @var array
43
     */
44
    protected $sizeRules = [
45
        'Between', 'Max', 'Min',
46
    ];
47
48
    /**
49
     * The validation rules that imply the field is required.
50
     * @var array
51
     */
52
    protected $implicitRules = [
53
        'Required',
54
    ];
55
56
    /**
57
     * The numeric related validation rules.
58
     * @var array
59
     */
60
    protected $numericRules = [
61
        'Number',
62
    ];
63
64
    /**
65
     * Run the validator's rules against its data.
66
     * @param mixed $data
67
     * @return array
68
     */
69 1
    public function validate($data, array $rules = [])
70
    {
71 1
        $this->normalizeData($data);
72 1
        $this->setRules($rules);
73 1
        foreach ($this->rules as $attribute => $rules) {
74 1
            foreach ($rules as $rule) {
75 1
                $this->validateAttribute($attribute, $rule);
76 1
                if ($this->shouldStopValidating($attribute)) {
77 1
                    break;
78
                }
79
            }
80
        }
81 1
        return $this->errors;
82
    }
83
84
    /**
85
     * Validate a given attribute against a rule.
86
     * @param string $attribute
87
     * @param string $rule
88
     * @return void
89
     * @throws BadMethodCallException
90
     */
91 1
    public function validateAttribute($attribute, $rule)
92
    {
93 1
        list($rule, $parameters) = $this->parseRule($rule);
94 1
        if ('' == $rule) {
95
            return;
96
        }
97 1
        $value = $this->getValue($attribute);
98 1
        if (!method_exists($this, $method = 'validate'.$rule)) {
99
            throw new BadMethodCallException("Method [$method] does not exist.");
100
        }
101 1
        if (!$this->$method($value, $attribute, $parameters)) {
102
            $this->addFailure($attribute, $rule, $parameters);
103
        }
104 1
    }
105
106
    /**
107
     * Add an error message to the validator's collection of errors.
108
     * @param string $attribute
109
     * @param string $rule
110
     * @return void
111
     */
112
    protected function addError($attribute, $rule, array $parameters)
113
    {
114
        $message = $this->getMessage($attribute, $rule, $parameters);
115
        $this->errors[$attribute][] = $message;
116
    }
117
118
    /**
119
     * Add a failed rule and error message to the collection.
120
     * @param string $attribute
121
     * @param string $rule
122
     * @return void
123
     */
124
    protected function addFailure($attribute, $rule, array $parameters)
125
    {
126
        $this->addError($attribute, $rule, $parameters);
127
        $this->failedRules[$attribute][$rule] = $parameters;
128
    }
129
130
    /**
131
     * Get the data type of the given attribute.
132
     * @param string $attribute
133
     * @return string
134
     */
135
    protected function getAttributeType($attribute)
136
    {
137
        return !$this->hasRule($attribute, $this->numericRules)
138
            ? 'length'
139
            : '';
140
    }
141
142
    /**
143
     * Get the validation message for an attribute and rule.
144
     * @param string $attribute
145
     * @param string $rule
146
     * @return string|null
147
     */
148
    protected function getMessage($attribute, $rule, array $parameters)
149
    {
150
        if (in_array($rule, $this->sizeRules)) {
151
            return $this->getSizeMessage($attribute, $rule, $parameters);
152
        }
153
        $lowerRule = glsr(Helper::class)->snakeCase($rule);
154
        return $this->translator($lowerRule, $parameters);
155
    }
156
157
    /**
158
     * Get a rule and its parameters for a given attribute.
159
     * @param string $attribute
160
     * @param string|array $rules
161
     * @return array|null
162
     */
163 1
    protected function getRule($attribute, $rules)
164
    {
165 1
        if (!array_key_exists($attribute, $this->rules)) {
166
            return;
167
        }
168 1
        $rules = (array) $rules;
169 1
        foreach ($this->rules[$attribute] as $rule) {
170 1
            list($rule, $parameters) = $this->parseRule($rule);
171 1
            if (in_array($rule, $rules)) {
172 1
                return [$rule, $parameters];
173
            }
174
        }
175 1
    }
176
177
    /**
178
     * Get the size of an attribute.
179
     * @param string $attribute
180
     * @param mixed $value
181
     * @return mixed
182
     */
183 1
    protected function getSize($attribute, $value)
184
    {
185 1
        $hasNumeric = $this->hasRule($attribute, $this->numericRules);
186 1
        if (is_numeric($value) && $hasNumeric) {
187 1
            return $value;
188
        } elseif (is_array($value)) {
189
            return count($value);
190
        }
191
        return function_exists('mb_strlen')
192
            ? mb_strlen($value)
193
            : strlen($value);
194
    }
195
196
    /**
197
     * Get the proper error message for an attribute and size rule.
198
     * @param string $attribute
199
     * @param string $rule
200
     * @return string|null
201
     */
202
    protected function getSizeMessage($attribute, $rule, array $parameters)
203
    {
204
        $type = $this->getAttributeType($attribute);
205
        $lowerRule = glsr(Helper::class)->snakeCase($rule.$type);
206
        return $this->translator($lowerRule, $parameters);
207
    }
208
209
    /**
210
     * Get the value of a given attribute.
211
     * @param string $attribute
212
     * @return mixed
213
     */
214 1
    protected function getValue($attribute)
215
    {
216 1
        if (isset($this->data[$attribute])) {
217 1
            return $this->data[$attribute];
218
        }
219
    }
220
221
    /**
222
     * Determine if the given attribute has a rule in the given set.
223
     * @param string $attribute
224
     * @param string|array $rules
225
     * @return bool
226
     */
227 1
    protected function hasRule($attribute, $rules)
228
    {
229 1
        return !is_null($this->getRule($attribute, $rules));
230
    }
231
232
    /**
233
     * Normalize the provided data to an array.
234
     * @param mixed $data
235
     * @return void
236
     */
237 1
    protected function normalizeData($data)
238
    {
239 1
        $this->data = is_object($data)
240
            ? get_object_vars($data)
241 1
            : $data;
242 1
    }
243
244
    /**
245
     * Parse a parameter list.
246
     * @param string $rule
247
     * @param string $parameter
248
     * @return array
249
     */
250 1
    protected function parseParameters($rule, $parameter)
251
    {
252 1
        return 'regex' == strtolower($rule)
253
            ? [$parameter]
254 1
            : str_getcsv($parameter);
255
    }
256
257
    /**
258
     * Extract the rule name and parameters from a rule.
259
     * @param string $rule
260
     * @return array
261
     */
262 1
    protected function parseRule($rule)
263
    {
264 1
        $parameters = [];
265 1
        if (false !== strpos($rule, ':')) {
266 1
            list($rule, $parameter) = explode(':', $rule, 2);
267 1
            $parameters = $this->parseParameters($rule, $parameter);
268
        }
269 1
        $rule = glsr(Helper::class)->camelCase($rule);
270 1
        return [$rule, $parameters];
271
    }
272
273
    /**
274
     * Set the validation rules.
275
     * @return void
276
     */
277 1
    protected function setRules(array $rules)
278
    {
279 1
        foreach ($rules as $key => $rule) {
280 1
            $rules[$key] = is_string($rule)
281 1
                ? explode('|', $rule)
282 1
                : $rule;
283
        }
284 1
        $this->rules = $rules;
285 1
    }
286
287
    /**
288
     * Check if we should stop further validations on a given attribute.
289
     * @param string $attribute
290
     * @return bool
291
     */
292 1
    protected function shouldStopValidating($attribute)
293
    {
294 1
        return $this->hasRule($attribute, $this->implicitRules)
295 1
            && isset($this->failedRules[$attribute])
296 1
            && array_intersect(array_keys($this->failedRules[$attribute]), $this->implicitRules);
297
    }
298
299
    /**
300
     * Returns a translated message for the attribute.
301
     * @param string $key
302
     * @param string $attribute
303
     * @return void|string
304
     */
305
    protected function translator($key, array $parameters)
306
    {
307
        $strings = glsr(ValidationStringsDefaults::class)->defaults();
308
        if (isset($strings[$key])) {
309
            return $this->replace($strings[$key], $parameters);
310
        }
311
        return 'error';
312
    }
313
}
314