Passed
Push — master ( 57b58d...3a36e2 )
by Paul
05:40
created

Validator::getSizeMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 3
dl 0
loc 5
ccs 0
cts 4
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\Helpers\Str;
9
use GeminiLabs\SiteReviews\Modules\Validator\ValidationRules;
10
11
/**
12
 * @see \Illuminate\Validation\Validator (5.3)
13
 */
14
class Validator
15
{
16
    use ValidationRules;
17
18
    /**
19
     * @var array
20
     */
21
    public $errors = [];
22
23
    /**
24
     * The data under validation.
25
     * @var array
26
     */
27
    protected $data = [];
28
29
    /**
30
     * The failed validation rules.
31
     * @var array
32
     */
33
    protected $failedRules = [];
34
35
    /**
36
     * The rules to be applied to the data.
37
     * @var array
38
     */
39
    protected $rules = [];
40
41
    /**
42
     * The size related validation rules.
43
     * @var array
44
     */
45
    protected $sizeRules = [
46
        'Between', 'Max', 'Min',
47
    ];
48
49
    /**
50
     * The validation rules that imply the field is required.
51
     * @var array
52
     */
53
    protected $implicitRules = [
54
        'Required',
55
    ];
56
57
    /**
58
     * The numeric related validation rules.
59
     * @var array
60
     */
61
    protected $numericRules = [
62
        'Number',
63
    ];
64
65
    /**
66
     * Run the validator's rules against its data.
67
     * @param mixed $data
68
     * @return array
69
     */
70 2
    public function validate($data, array $rules = [])
71
    {
72 2
        $this->normalizeData($data);
73 2
        $this->setRules($rules);
74 2
        foreach ($this->rules as $attribute => $rules) {
75 2
            foreach ($rules as $rule) {
76 2
                $this->validateAttribute($attribute, $rule);
77 2
                if ($this->shouldStopValidating($attribute)) {
78 2
                    break;
79
                }
80
            }
81
        }
82 2
        return $this->errors;
83
    }
84
85
    /**
86
     * Validate a given attribute against a rule.
87
     * @param string $attribute
88
     * @param string $rule
89
     * @return void
90
     * @throws BadMethodCallException
91
     */
92 2
    public function validateAttribute($attribute, $rule)
93
    {
94 2
        list($rule, $parameters) = $this->parseRule($rule);
95 2
        if ('' == $rule) {
96
            return;
97
        }
98 2
        $value = $this->getValue($attribute);
99 2
        $method = Helper::buildMethodName($rule, 'validate');
100 2
        if (!method_exists($this, $method)) {
101
            throw new BadMethodCallException("Method [$method] does not exist.");
102
        }
103 2
        if (!$this->$method($value, $attribute, $parameters)) {
104 2
            $this->addFailure($attribute, $rule, $parameters);
105
        }
106 2
    }
107
108
    /**
109
     * Add an error message to the validator's collection of errors.
110
     * @param string $attribute
111
     * @param string $rule
112
     * @return void
113
     */
114 2
    protected function addError($attribute, $rule, array $parameters)
115
    {
116 2
        $message = $this->getMessage($attribute, $rule, $parameters);
117 2
        $this->errors[$attribute][] = $message;
118 2
    }
119
120
    /**
121
     * Add a failed rule and error message to the collection.
122
     * @param string $attribute
123
     * @param string $rule
124
     * @return void
125
     */
126 2
    protected function addFailure($attribute, $rule, array $parameters)
127
    {
128 2
        $this->addError($attribute, $rule, $parameters);
129 2
        $this->failedRules[$attribute][$rule] = $parameters;
130 2
    }
131
132
    /**
133
     * Get the data type of the given attribute.
134
     * @param string $attribute
135
     * @return string
136
     */
137
    protected function getAttributeType($attribute)
138
    {
139
        return !$this->hasRule($attribute, $this->numericRules)
140
            ? 'length'
141
            : '';
142
    }
143
144
    /**
145
     * Get the validation message for an attribute and rule.
146
     * @param string $attribute
147
     * @param string $rule
148
     * @return string|null
149
     */
150 2
    protected function getMessage($attribute, $rule, array $parameters)
151
    {
152 2
        if (in_array($rule, $this->sizeRules)) {
153
            return $this->getSizeMessage($attribute, $rule, $parameters);
154
        }
155 2
        $lowerRule = Str::snakeCase($rule);
156 2
        return $this->translator($lowerRule, $parameters);
157
    }
158
159
    /**
160
     * Get a rule and its parameters for a given attribute.
161
     * @param string $attribute
162
     * @param string|array $rules
163
     * @return array|null|void
164
     */
165 2
    protected function getRule($attribute, $rules)
166
    {
167 2
        if (!array_key_exists($attribute, $this->rules)) {
168
            return;
169
        }
170 2
        $rules = (array) $rules;
171 2
        foreach ($this->rules[$attribute] as $rule) {
172 2
            list($rule, $parameters) = $this->parseRule($rule);
173 2
            if (in_array($rule, $rules)) {
174 2
                return [$rule, $parameters];
175
            }
176
        }
177 2
    }
178
179
    /**
180
     * Get the size of an attribute.
181
     * @param string $attribute
182
     * @param mixed $value
183
     * @return mixed
184
     */
185 1
    protected function getSize($attribute, $value)
186
    {
187 1
        $hasNumeric = $this->hasRule($attribute, $this->numericRules);
188 1
        if (is_numeric($value) && $hasNumeric) {
189 1
            return $value;
190
        } elseif (is_array($value)) {
191
            return count($value);
192
        }
193
        return mb_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 = Str::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 2
    protected function getValue($attribute)
215
    {
216 2
        if (isset($this->data[$attribute])) {
217 2
            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 2
    protected function hasRule($attribute, $rules)
228
    {
229 2
        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 2
    protected function normalizeData($data)
238
    {
239 2
        $this->data = is_object($data)
240
            ? get_object_vars($data)
241 2
            : $data;
242 2
    }
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 2
    protected function parseRule($rule)
263
    {
264 2
        $parameters = [];
265 2
        if (Str::contains(':', $rule)) {
266 1
            list($rule, $parameter) = explode(':', $rule, 2);
267 1
            $parameters = $this->parseParameters($rule, $parameter);
268
        }
269 2
        $rule = Str::camelCase($rule);
270 2
        return [$rule, $parameters];
271
    }
272
273
    /**
274
     * Set the validation rules.
275
     * @return void
276
     */
277 2
    protected function setRules(array $rules)
278
    {
279 2
        foreach ($rules as $key => $rule) {
280 2
            $rules[$key] = is_string($rule)
281 2
                ? explode('|', $rule)
282
                : $rule;
283
        }
284 2
        $this->rules = $rules;
285 2
    }
286
287
    /**
288
     * Check if we should stop further validations on a given attribute.
289
     * @param string $attribute
290
     * @return bool
291
     */
292 2
    protected function shouldStopValidating($attribute)
293
    {
294 2
        return $this->hasRule($attribute, $this->implicitRules)
295 2
            && isset($this->failedRules[$attribute])
296 2
            && 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
     * @return void|string
303
     */
304 2
    protected function translator($key, array $parameters)
305
    {
306 2
        $strings = glsr(ValidationStringsDefaults::class)->defaults();
307 2
        if (isset($strings[$key])) {
308 2
            return $this->replace($strings[$key], $parameters);
309
        }
310
        return 'error';
311
    }
312
}
313