Passed
Push — master ( b58af5...61319a )
by AJ
01:56
created

Validation::validateBoolean()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
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 46
    public static function validate($array, $rules)
35
    {
36 46
        if (is_array($array) && is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
37 44
            self::checkRequired($array, $rules);
38 40
            foreach ($array as $key => $value) {
39 38
                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 38
                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 38
                } elseif (in_array($key, array_keys($rules))) {
46 40
                    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 34
        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 44
    protected static function checkRequired($array, $rules)
69
    {
70 44
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
71 44
            foreach ($rules as $key => $value) {
72 42
                if (self::requiredNull($array, $key)) {
73 18
                    if (isset($value['required'])) {
74 10
                        if (is_array($value['required']) && !self::requiredOne($array, $value['required'])) {
75
                            //
76 10
                        } elseif (($value['required'] == 'true' || $value['required'] === true) && isset($array[$key])) {
77
                            //
78
                        } else {
79 42
                            throw new Exception(sprintf('Required value not found for key: %s.', $key));
80
                        }
81
                    }
82
                }
83
            }
84
        }
85
86 40
        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 42
    protected static function requiredNull($array, $key)
97
    {
98 42
        if ((!isset($array[$key]) && !array_key_exists($key, $array))
99 40
            || ((isset($array[$key]) || array_key_exists($key, $array))
100 42
                && ($array[$key] === null || $array[$key] === 'null'))
101
        ) {
102 18
            return true;
103
        }
104
105 36
        return false;
106
    }
107
108
    /**
109
     * Returns true if one of the conditions comes back as requiring the key being tested
110
     * to be required. Returns false if all the conditions find that checks do not require
111
     * the key value to be present.
112
     *
113
     * @param array $array
114
     * @param array $rules
115
     * @return true|false
116
     */
117 6
    protected static function requiredOne($array, $rules)
118
    {
119 6
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
120 6
            foreach ($rules as $key => $value) {
121 6
                if ((is_array($value) && self::requiredAll($array, $value)) || self::requiredTest($array, $value, $key)) {
122 6
                    return true;
123
                }
124
            }
125
        }
126 4
        return false;
127
    }
128
129
    /**
130
     * Checks an array of $rules and returns false if any one of the rules fails.
131
     * If all rule tests pass, then the method returns true.
132
     *
133
     * @param array $array
134
     * @param array $rules
135
     * @return true|false
136
     */
137 2
    protected static function requiredAll($array, $rules)
138
    {
139 2
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
140 2
            foreach ($rules as $key => $value) {
141 2
                if (!self::requiredTest($array, $value, $key)) {
142 2
                    return false;
143
                }
144
            }
145
        }
146
147 2
        return true;
148
    }
149
150
    /**
151
     * Returns output of testing functions. Will return true if $key is required
152
     * false if the $key is not required.
153
     *
154
     * @param $array
155
     * @param $value
156
     * @param $key
157
     * @return true|false
158
     */
159 6
    protected static function requiredTest($array, $value, $key)
160
    {
161 6
        if (is_null($value) || $value == 'null') {
162 4
            return self::requiredNull($array, $key);
163 2
        } elseif (isset($array[$key]) && $array[$key] == $value) {
164 2
            return true;
165
        }
166
167 2
        return false;
168
    }
169
170
    /**
171
     * @param string $value
172
     * @param array $rules
173
     * @param string $key
174
     * @return true
175
     * @throws Exception
176
     */
177 38
    public static function validateField($value, $rules, $key)
178
    {
179 38
        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...
180 6
            foreach ($value as $k => $v) {
181 6
                if (is_array($v) && !isset($rules['fields'][$k])) {
182 6
                    self::validate($v, $rules['fields']);
183 2
                } elseif (isset($rules['fields'][$k])) {
184 6
                    self::validateField($v, $rules['fields'][$k], $k);
185
                }
186
            }
187 38
        } elseif (is_array($value)) {
0 ignored issues
show
introduced by
The condition is_array($value) is always false.
Loading history...
188 4
            throw new Exception(sprintf('Unexpected array found for key: %s.', $key));
189
        }
190
191 36
        if (isset($value) && $value !== null && $value != 'null') {
192 32
            if (isset($rules['type'])) {
193 32
                if ($rules['type'] === 'integer') {
194 6
                    self::validateInteger($value, $key);
0 ignored issues
show
Bug introduced by
$value of type string is incompatible with the type integer expected by parameter $value of Multidimensional\ArrayVa...tion::validateInteger(). ( Ignorable by Annotation )

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

194
                    self::validateInteger(/** @scrutinizer ignore-type */ $value, $key);
Loading history...
195 30
                } elseif ($rules['type'] === 'decimal') {
196 6
                    self::validateDecimal($value, $key);
0 ignored issues
show
Bug introduced by
$value of type string is incompatible with the type double expected by parameter $value of Multidimensional\ArrayVa...tion::validateDecimal(). ( Ignorable by Annotation )

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

196
                    self::validateDecimal(/** @scrutinizer ignore-type */ $value, $key);
Loading history...
197 28
                } elseif ($rules['type'] === 'string') {
198 26
                    self::validateString($value, $key);
199 10
                } elseif ($rules['type'] === 'boolean') {
200 2
                    self::validateBoolean($value, $key);
0 ignored issues
show
Bug introduced by
$value of type string is incompatible with the type boolean expected by parameter $value of Multidimensional\ArrayVa...tion::validateBoolean(). ( Ignorable by Annotation )

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

200
                    self::validateBoolean(/** @scrutinizer ignore-type */ $value, $key);
Loading history...
201
                }
202
            }
203
204 32
            if (isset($rules['values'])) {
205 10
                self::validateValues($value, $rules['values'], $key);
206
            }
207
208 30
            if (isset($rules['pattern'])) {
209 6
                if ($rules['pattern'] == 'ISO 8601') {
210 2
                    self::validateISO8601($value, $key);
211
                } else {
212 6
                    self::validatePattern($value, $rules['pattern'], $key);
213
                }
214
            }
215
        }
216
217 34
        return true;
218
    }
219
220
    /**
221
     * @param int $value
222
     * @param string|null $key
223
     * @return true|false
224
     * @throws Exception
225
     */
226 6
    protected static function validateInteger($value, $key)
227
    {
228 6
        if (!is_int($value)) {
0 ignored issues
show
introduced by
The condition is_int($value) is always true.
Loading history...
229 2
            throw new Exception(sprintf('Invalid integer "%s" for key: %s.', $value, $key));
230
        }
231
232 6
        return true;
233
    }
234
235
    /**
236
     * @param float $value
237
     * @param string|null $key
238
     * @return true|false
239
     * @throws Exception
240
     */
241 6
    protected static function validateDecimal($value, $key)
242
    {
243 6
        if (!is_float($value)) {
0 ignored issues
show
introduced by
The condition is_float($value) is always true.
Loading history...
244 2
            throw new Exception(sprintf('Invalid decimal "%s" for key: %s.', $value, $key));
245
        }
246
247 6
        return true;
248
    }
249
250
    /**
251
     * @param string $value
252
     * @param string|null $key
253
     * @return true|false
254
     * @throws Exception
255
     */
256 26
    protected static function validateString($value, $key)
257
    {
258 26
        if (!is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
259 2
            throw new Exception(sprintf('Invalid string "%s" for key: %s.', $value, $key));
260
        }
261
262 26
        return true;
263
    }
264
265
    /**
266
     * @param bool $value
267
     * @param string|null $key
268
     * @return true
269
     * @throws Exception
270
     */
271 2
    protected static function validateBoolean($value, $key)
272
    {
273 2
        if (!is_bool($value)) {
0 ignored issues
show
introduced by
The condition is_bool($value) is always true.
Loading history...
274 2
            throw new Exception(sprintf('Invalid boolean "%s" for key: %s.', $value, $key));
275
        }
276
277 2
        return true;
278
    }
279
280
    /**
281
     * @param string $value
282
     * @param array|string $array
283
     * @param string|null $key
284
     * @return bool
285
     * @throws Exception
286
     */
287 10
    protected static function validateValues($value, $array, $key)
288
    {
289 10
        $compareArray = [];
290 10
        if (is_array($array)) {
291 8
            foreach ($array as $compareKey) {
292 8
                $compareScore = levenshtein($value, $compareKey);
293 8
                $compareArray[$compareKey] = $compareScore;
294 8
                if ($compareScore === 0) {
295 8
                    return true;
296
                }
297
            }
298 2
        } elseif (strcasecmp($value, $array) === 0) {
299 2
            return true;
300
        }
301
302 2
        $errorMessage = sprintf('Invalid value "%s" for key: %s.', $value, $key);
303
304 1
        array_walk($compareArray, function (&$item) {
305 2
            $item = abs($item);
306 2
        });
307 2
        asort($compareArray);
308 2
        $compareArray = array_keys($compareArray);
309 2
        if (count($compareArray)) {
310 2
            $errorMessage .= sprintf(' Did you mean "%s"?', array_shift($compareArray));
311
        }
312
313 2
        throw new Exception($errorMessage);
314
    }
315
316
    /**
317
     * @param string $value
318
     * @param string $key
319
     * @return bool
320
     * @throws Exception
321
     */
322 2
    protected static function validateISO8601($value, $key)
323
    {
324 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)';
325 2
        if (!preg_match('/^' . $pattern . '$/', $value)) {
326 2
            throw new Exception(sprintf('Invalid value "%s" does not match ISO 8601 pattern for key: %s.', $value, $key));
327
        }
328
329 2
        return true;
330
    }
331
332
    /**
333
     * @param string $value
334
     * @param string $pattern
335
     * @param string $key
336
     * @return bool
337
     * @throws Exception
338
     */
339 6
    protected static function validatePattern($value, $pattern, $key)
340
    {
341 6
        if (!preg_match('/^' . $pattern . '$/', $value)) {
342 2
            throw new Exception(sprintf('Invalid value "%s" does not match pattern "%s" for key: %s.', $value, $pattern, $key));
343
        }
344
345 6
        return true;
346
    }
347
}
348