Validation::validateField()   F
last analyzed

Complexity

Conditions 29
Paths 145

Size

Total Lines 51
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 29

Importance

Changes 0
Metric Value
cc 29
eloc 36
nc 145
nop 3
dl 0
loc 51
ccs 35
cts 35
cp 1
crap 29
rs 3.7916
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 *       __  ___      ____  _     ___                           _                    __
4
 *      /  |/  /_  __/ / /_(_)___/ (_)___ ___  ___  ____  _____(_)___  ____   ____ _/ /
5
 *     / /|_/ / / / / / __/ / __  / / __ `__ \/ _ \/ __ \/ ___/ / __ \/ __ \ / __ `/ /
6
 *    / /  / / /_/ / / /_/ / /_/ / / / / / / /  __/ / / (__  ) / /_/ / / / // /_/ / /
7
 *   /_/  /_/\__,_/_/\__/_/\__,_/_/_/ /_/ /_/\___/_/ /_/____/_/\____/_/ /_(_)__,_/_/
8
 *
9
 *  Array Validation Library
10
 *  Copyright (c) Multidimension.al (http://multidimension.al)
11
 *  Github : https://github.com/multidimension-al/array-validation
12
 *
13
 *  Licensed under The MIT License
14
 *  For full copyright and license information, please see the LICENSE file
15
 *  Redistributions of files must retain the above copyright notice.
16
 *
17
 *  @copyright  Copyright © 2017-2019 Multidimension.al (http://multidimension.al)
18
 *  @link       https://github.com/multidimension-al/array-validation Github
19
 *  @license    http://www.opensource.org/licenses/mit-license.php MIT License
20
 */
21
22
namespace Multidimensional\ArrayValidation;
23
24
use Exception;
25
26
class Validation
27
{
28
    /**
29
     * @param array $array
30
     * @param array $rules
31
     * @return true
32
     * @throws Exception
33
     */
34 60
    public static function validate($array, $rules)
35
    {
36 60
        if (is_array($array) && is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
37 58
            self::checkRequired($array, $rules);
38 52
            foreach ($array as $key => $value) {
39 50
                if (!isset($rules[$key]) && !array_key_exists($key, $rules)) {
40 2
                    throw new Exception(sprintf('Unexpected key "%s" found in array.', $key));
41
                }
42
43 50
                if (is_array($value) && isset($rules[$key]['type']) && strtolower($rules[$key]['type']) == 'array' && isset($rules[$key]['fields'])) {
44 6
                    self::validate($value, $rules[$key]['fields']);
45 50
                } elseif (in_array($key, array_keys($rules))) {
46 51
                    self::validateField($value, $rules[$key], $key);
47
                }
48
            }
49 2
        } elseif (!is_array($array)) {
50 2
            throw new Exception('Validation array not found.');
51 2
        } elseif (!is_array($rules)) {
52 2
            throw new Exception('Validation rules array not found.');
53
        }
54
55 44
        return true;
56
    }
57
58
    /**
59
     * Main required check function. Must be fed with two variables, both of type array.
60
     * Returns void if all checks pass without a Exception being thrown. Only
61
     * performs checkRequired operation on values that are not set in the main $array.
62
     *
63
     * @param array $array Validation Array comprised of key / value pairs to be checked.
64
     * @param array $rules Rules Array comprised of properly formatted keys with rules.
65
     * @return void
66
     * @throws Exception
67
     */
68 58
    protected static function checkRequired($array, $rules)
69
    {
70 58
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
71 58
            foreach ($rules as $key => $value) {
72 56
                if (self::requiredNull($array, $key) || self::requiredEmpty($array, $key)) {
73 34
                    if (isset($value['required'])) {
74 18
                        if (is_array($value['required']) && !self::requiredOne($array, $value['required'])) {
75
                            //
76 18
                        } elseif (($value['required'] == 'true' || $value['required'] === true) && isset($array[$key]) && (!empty($array[$key]) || is_numeric($array[$key]))) {
77
                            //
78
                        } else {
79 35
                            throw new Exception(sprintf('Required value not found for key: %s.', $key));
80
                        }
81
                    }
82
                }
83
            }
84
        }
85
86 52
        return;
87
    }
88
89
    /**
90
     * Returns true when $key value is null, returns false when it is not.
91
     *
92
     * @param array $array
93
     * @param string $key
94
     * @return true|false
95
     */
96 56
    protected static function requiredNull($array, $key)
97
    {
98 56
        if ((!isset($array[$key]) && !array_key_exists($key, $array))
99 52
            || ((isset($array[$key]) || array_key_exists($key, $array))
100 56
                && ($array[$key] === null || $array[$key] === 'null'))
101
        ) {
102 22
            return true;
103
        }
104
105 48
        return false;
106
    }
107
108
    /**
109
     * Returns true when $key value is null, returns false when it is not.
110
     *
111
     * @param array $array
112
     * @param string $key
113
     * @return true|false
114
     */
115 50
    protected static function requiredEmpty($array, $key)
116
    {
117 50
        if ((!isset($array[$key]) && !array_key_exists($key, $array))
118 48
            || ((isset($array[$key]) || array_key_exists($key, $array))
119 50
                && (empty($array[$key] && !is_numeric($array[$key]))))
120
        ) {
121 20
            return true;
122
        }
123
124 46
        return false;
125
    }
126
127
    /**
128
     * Returns true if one of the conditions comes back as requiring the key being tested
129
     * to be required. Returns false if all the conditions find that checks do not require
130
     * the key value to be present.
131
     *
132
     * @param array $array
133
     * @param array $rules
134
     * @return true|false
135
     */
136 8
    protected static function requiredOne($array, $rules)
137
    {
138 8
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
139 8
            foreach ($rules as $key => $value) {
140 8
                if ((is_array($value) && self::requiredAll($array, $value)) || self::requiredTest($array, $value, $key)) {
141 8
                    return true;
142
                }
143
            }
144
        }
145 4
        return false;
146
    }
147
148
    /**
149
     * Checks an array of $rules and returns false if any one of the rules fails.
150
     * If all rule tests pass, then the method returns true.
151
     *
152
     * @param array $array
153
     * @param array $rules
154
     * @return true|false
155
     */
156 2
    protected static function requiredAll($array, $rules)
157
    {
158 2
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
159 2
            foreach ($rules as $key => $value) {
160 2
                if (!self::requiredTest($array, $value, $key)) {
161 2
                    return false;
162
                }
163
            }
164
        }
165
166 2
        return true;
167
    }
168
169
    /**
170
     * Returns output of testing functions. Will return true if $key is required
171
     * false if the $key is not required.
172
     *
173
     * @param $array
174
     * @param $value
175
     * @param $key
176
     * @return true|false
177
     */
178 8
    protected static function requiredTest($array, $value, $key)
179
    {
180 8
        if (is_null($value) || $value == 'null') {
181 4
            return self::requiredNull($array, $key);
182 4
        } elseif (empty($value) && !is_numeric($value)) {
183 2
            return self::requiredEmpty($array, $key);
184 2
        } elseif (isset($array[$key]) && $array[$key] == $value) {
185 2
            return true;
186
        }
187
188 2
        return false;
189
    }
190
191
    /**
192
     * @param string $value
193
     * @param array $rules
194
     * @param string $key
195
     * @return true
196
     * @throws Exception
197
     */
198 50
    public static function validateField($value, $rules, $key)
199
    {
200 50
        if (is_array($value) && isset($rules['type']) && strtolower($rules['type']) == 'group' && isset($rules['fields'])) {
0 ignored issues
show
introduced by
The condition is_array($value) is always false.
Loading history...
201 6
            foreach ($value as $k => $v) {
202 6
                if (is_array($v) && !isset($rules['fields'][$k])) {
203 6
                    self::validate($v, $rules['fields']);
204 2
                } elseif (isset($rules['fields'][$k])) {
205 4
                    self::validateField($v, $rules['fields'][$k], $k);
206
                }
207
            }
208 50
        } elseif (is_array($value)) {
0 ignored issues
show
introduced by
The condition is_array($value) is always false.
Loading history...
209 4
            throw new Exception(sprintf('Unexpected array found for key: %s.', $key));
210
        }
211
212 48
        if (isset($value) && $value !== null && $value != 'null' && (!empty($value) || is_numeric($value))) {
213 44
            if (isset($rules['type']) && $rules['type'] != 'group') {
214 44
                if ($rules['type'] === 'integer') {
215 8
                    self::validateInteger($value, $key);
216 42
                } elseif ($rules['type'] === 'decimal') {
217 6
                    self::validateDecimal($value, $key);
218 40
                } elseif ($rules['type'] === 'string') {
219 36
                    self::validateString($value, $key);
220 4
                } elseif ($rules['type'] === 'boolean') {
221 2
                    self::validateBoolean($value, $key);
222
                } else {
223 2
                    throw new Exception(sprintf('Invalid type "%s" for key: %s.', $rules['type'], $key));
224
                }
225
            }
226
227 40
            if (isset($rules['values'])) {
228 10
                self::validateValues($value, $rules['values'], $key);
229
            }
230
231 38
            if (isset($rules['pattern'])) {
232 16
                if (strtoupper($rules['pattern']) == 'ISO 8601' || strtoupper($rules['pattern']) == 'ISO8601') {
233 2
                    self::validateISO8601($value, $key);
234 16
                } else if (strtoupper($rules['pattern']) == 'URL') {
235 2
                    self::validateURL($value, $key);
236 14
                } else if (strtoupper($rules['pattern']) == 'EMAIL') {
237 2
                    self::validateEmail($value, $key);
238 12
                } else if (strtoupper($rules['pattern']) == 'IP') {
239 4
                    self::validateIP($value, $key);
240 10
                } else if (strtoupper($rules['pattern']) == 'MAC') {
241 2
                    self::validateMAC($value, $key);
242
                } else {
243 8
                    self::validatePattern($value, $rules['pattern'], $key);
244
                }
245
            }
246
        }
247
248 44
        return true;
249
    }
250
251
    /**
252
     * @param int $value
253
     * @param string|null $key
254
     * @return true|false
255
     * @throws Exception
256
     */
257 8
    protected static function validateInteger($value, $key)
258
    {
259 8
        if (!is_int($value)) {
0 ignored issues
show
introduced by
The condition is_int($value) is always true.
Loading history...
260 2
            throw new Exception(sprintf('Invalid integer "%s" for key: %s.', $value, $key));
261
        }
262
263 8
        return true;
264
    }
265
266
    /**
267
     * @param float $value
268
     * @param string|null $key
269
     * @return true|false
270
     * @throws Exception
271
     */
272 6
    protected static function validateDecimal($value, $key)
273
    {
274 6
        if (!is_float($value)) {
0 ignored issues
show
introduced by
The condition is_float($value) is always true.
Loading history...
275 2
            throw new Exception(sprintf('Invalid decimal "%s" for key: %s.', $value, $key));
276
        }
277
278 6
        return true;
279
    }
280
281
    /**
282
     * @param string $value
283
     * @param string|null $key
284
     * @return true|false
285
     * @throws Exception
286
     */
287 36
    protected static function validateString($value, $key)
288
    {
289 36
        if (!is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
290 2
            throw new Exception(sprintf('Invalid string "%s" for key: %s.', $value, $key));
291
        }
292
293 36
        return true;
294
    }
295
296
    /**
297
     * @param bool $value
298
     * @param string|null $key
299
     * @return true
300
     * @throws Exception
301
     */
302 2
    protected static function validateBoolean($value, $key)
303
    {
304 2
        if (!is_bool($value)) {
0 ignored issues
show
introduced by
The condition is_bool($value) is always true.
Loading history...
305 2
            throw new Exception(sprintf('Invalid boolean "%s" for key: %s.', $value, $key));
306
        }
307
308
        return true;
309
    }
310
311
    /**
312
     * @param string $value
313
     * @param array|string $array
314
     * @param string|null $key
315
     * @return bool
316
     * @throws Exception
317
     */
318 10
    protected static function validateValues($value, $array, $key)
319
    {
320 10
        $compareArray = [];
321 10
        if (is_array($array)) {
322 8
            foreach ($array as $compareKey) {
323 8
                $compareScore = levenshtein($value, $compareKey);
324 8
                $compareArray[$compareKey] = $compareScore;
325 8
                if ($compareScore === 0) {
326 7
                    return true;
327
                }
328
            }
329 2
        } elseif (strcasecmp($value, $array) === 0) {
330 2
            return true;
331
        }
332
333 2
        $errorMessage = sprintf('Invalid value "%s" for key: %s.', $value, $key);
334
335 1
        array_walk($compareArray, function(&$item) {
336 2
            $item = abs($item);
337 2
        });
338 2
        asort($compareArray);
339 2
        $compareArray = array_keys($compareArray);
340 2
        if (count($compareArray)) {
341 2
            $errorMessage .= sprintf(' Did you mean "%s"?', array_shift($compareArray));
342
        }
343
344 2
        throw new Exception($errorMessage);
345
    }
346
347
    /**
348
     * @param string $value
349
     * @param string $key
350
     * @return bool
351
     * @throws Exception
352
     */
353 2
    protected static function validateISO8601($value, $key)
354
    {
355 2
        $pattern = '(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:Z|[+-][01]\d:[0-5]\d)';
356 2
        if (!preg_match('/^'.$pattern.'$/', $value)) {
357 2
            throw new Exception(sprintf('Invalid value "%s" does not match ISO 8601 pattern for key: %s.', $value, $key));
358
        }
359
360 2
        return true;
361
    }
362
363
    /**
364
     * @param string $value
365
     * @param string $key
366
     * @return bool
367
     * @throws Exception
368
     */
369 2
    protected static function validateURL($value, $key)
370
    {
371 2
        if (!filter_var($value, FILTER_VALIDATE_URL)) {
372 2
            throw new Exception(sprintf('Invalid value "%s" does not match URL pattern for key: %s.', $value, $key));
373
        }
374
375 2
        return true;
376
    }
377
378
    /**
379
     * @param string $value
380
     * @param string $key
381
     * @return bool
382
     * @throws Exception
383
     */
384 2
    protected static function validateEmail($value, $key)
385
    {
386 2
        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
387 2
            throw new Exception(sprintf('Invalid value "%s" does not match email pattern for key: %s.', $value, $key));
388
        }
389
390 2
        return true;
391
    }
392
393
    /**
394
     * @param string $value
395
     * @param string $key
396
     * @return bool
397
     * @throws Exception
398
     */
399 4
    protected static function validateIP($value, $key)
400
    {
401 4
        if (!filter_var($value, FILTER_VALIDATE_IP)) {
402 2
            throw new Exception(sprintf('Invalid value "%s" does not match IP address pattern for key: %s.', $value, $key));
403
        }
404
405 4
        return true;
406
    }
407
408
    /**
409
     * @param string $value
410
     * @param string $key
411
     * @return bool
412
     * @throws Exception
413
     */
414 2
    protected static function validateMAC($value, $key)
415
    {
416 2
        if (!filter_var($value, FILTER_VALIDATE_MAC)) {
417 2
            throw new Exception(sprintf('Invalid value "%s" does not match MAC address pattern for key: %s.', $value, $key));
418
        }
419
420 2
        return true;
421
    }
422
423
424
    /**
425
     * @param string $value
426
     * @param string $pattern
427
     * @param string $key
428
     * @return bool
429
     * @throws Exception
430
     */
431 8
    protected static function validatePattern($value, $pattern, $key)
432
    {
433 8
        if (!preg_match('/^'.$pattern.'$/', $value)) {
434 2
            throw new Exception(sprintf('Invalid value "%s" does not match pattern "%s" for key: %s.', $value, $pattern, $key));
435
        }
436
437 8
        return true;
438
    }
439
}
440