Passed
Pull Request — master (#20)
by Mathieu
14:57 queued 10:09
created

Validator::pass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suricate;
6
7
use InvalidArgumentException;
8
use BadMethodCallException;
9
use Exception;
10
11
/**
12
 * Validator
13
 * Inspired from Kieron Wilson PHP Validator
14
 *
15
 * @method Validator true(string $errorMessage)
16
 * @method Validator false(string $errorMessage)
17
 * @method Validator equalTo(mixed $toTest, string $errorMessage)
18
 * @method Validator identicalTo(mixed $toTest, string $errorMessage)
19
 * @method Validator lessThan(mixed $toTest, string $errorMessage)
20
 * @method Validator lessThanOrEqual(mixed $toTest, string $errorMessage)
21
 * @method Validator greaterThan(mixed $toTest, string $errorMessage)
22
 * @method Validator greaterThanOrEqual(mixed $toTest, string $errorMessage)
23
 * @method Validator blank(string $errorMessage)
24
 * @method Validator null(string $errorMessage)
25
 * @method Validator type(string $testType, string $errorMessage)
26
 * &method Validator email(string $errorMessage)
27
 * &method Validator url(string $errorMessage)
28
 * &method Validator ip(string $errorMessage)
29
 * &method Validator regexp(string $errorMessage)
30
 * @author      Mathieu LESNIAK <[email protected]>
31
 * @copyright   Mathieu LESNIAK
32
 * @package     Suricate
33
 */
34
class Validator
35
{
36
    private $errors = [];
37
    private $checks = [];
38
    private $datas;
39
    private $value;
40
    private $index;
41
    private $stop = false;
42
43 15
    public function __construct($input)
44
    {
45 15
        $this->datas = $input;
46 15
        $this->value = $input;
47 15
        $this->createChecks();
48 15
    }
49
50
    /**
51
     * Initialize checks
52
     *
53
     * @return void
54
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
55
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
56
     */
57 15
    private function createChecks()
58
    {
59
        $this->checks['equalTo'] = function ($value, $compare) {
60 1
            return $value == $compare;
61
        };
62
63
        $this->checks['identicalTo'] = function ($value, $compare) {
64 1
            return $value === $compare;
65
        };
66
67
        $this->checks['lessThan'] = function ($value, $compare) {
68 1
            return $value < $compare;
69
        };
70
71
        $this->checks['lessThanOrEqual'] = function ($value, $compare) {
72 1
            return $value <= $compare;
73
        };
74
75
        $this->checks['greaterThan'] = function ($value, $compare) {
76 1
            return $value > $compare;
77
        };
78
79
        $this->checks['greaterThanOrEqual'] = function ($value, $compare) {
80 1
            return $value >= $compare;
81
        };
82
83
        $this->checks['blank'] = function ($value) {
84 1
            return $value == '';
85
        };
86
87
        $this->checks['null'] = function ($value) {
88 1
            return is_null($value);
89
        };
90
91
        $this->checks['true'] = function ($value) {
92 1
            return $value === true;
93
        };
94
95
        $this->checks['false'] = function ($value) {
96 1
            return !($value === true);
97
        };
98
99
        $this->checks['type'] = function ($value, $type) {
100 1
            switch ($type) {
101 1
                case 'array':
102 1
                    return is_array($value);
103 1
                case 'bool':
104 1
                    return is_bool($value);
105 1
                case 'callable':
106
                    return is_callable($value);
107 1
                case 'float':
108 1
                    return is_float($value);
109 1
                case 'int':
110 1
                    return is_int($value);
111 1
                case 'numeric':
112 1
                    return is_numeric($value);
113 1
                case 'object':
114 1
                    return is_object($value);
115 1
                case 'resource':
116
                    return is_resource($value);
117 1
                case 'scalar':
118
                    return is_scalar($value);
119 1
                case 'string':
120 1
                    return is_string($value);
121
                default:
122
                    throw new InvalidArgumentException(
123
                        'Unknown type to check ' . $type
124
                    );
125
            }
126
        };
127
128
        $this->checks['email'] = function ($value) {
129 1
            return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
130
        };
131
132
        $this->checks['url'] = function ($value) {
133 1
            return filter_var($value, FILTER_VALIDATE_URL) !== false;
134
        };
135
136
        $this->checks['ip'] = function ($value) {
137 1
            return filter_var($value, FILTER_VALIDATE_IP) !== false;
138
        };
139
140
        $this->checks['regexp'] = function ($value, $regexp) {
141
            return filter_var($value, FILTER_VALIDATE_REGEXP, [
142
                "options" => ['regexp' => $regexp]
143
            ]) !== false;
144
        };
145
146
        $this->checks['longerThan'] = function ($value, $length) {
147
            return strlen((string) $value) > $length;
148
        };
149
150
        $this->checks['longerThanOrEqual'] = function ($value, $length) {
151
            return strlen((string) $value) >= $length;
152
        };
153
154
        $this->checks['shorterThan'] = function ($value, $length) {
155
            return strlen((string) $value) < $length;
156
        };
157
158
        $this->checks['shortThanOrEqual'] = function ($value, $length) {
159
            return strlen((string) $value) <= $length;
160
        };
161
162
        $this->checks['contains'] = function ($value, $toFind) {
163
            return strpos((string) $value, $toFind) !== false;
164
        };
165
166
        $this->checks['alnum'] = function ($value) {
167 1
            return ctype_alnum($value);
168
        };
169
170
        $this->checks['alpha'] = function ($value) {
171
            return ctype_alpha($value);
172
        };
173
174
        $this->checks['digit'] = function ($value) {
175
            return ctype_digit($value);
176
        };
177
178
        $this->checks['lower'] = function ($value) {
179
            return ctype_lower($value);
180
        };
181
182
        $this->checks['upper'] = function ($value) {
183
            return ctype_upper($value);
184
        };
185
186
        $this->checks['space'] = function ($value) {
187
            return ctype_space($value);
188
        };
189 15
    }
190
191
    public function validate($index = null)
192
    {
193
        if ($index === null) {
194
            $this->value = $this->datas;
195
            $this->index = null;
196
            return $this;
197
        }
198
199
        if (is_object($this->datas)) {
200
            try {
201
                $this->value = $this->datas->$index;
202
            } catch (Exception $e) {
0 ignored issues
show
Unused Code introduced by
catch (\Exception $e) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
203
                throw new InvalidArgumentException(
204
                    'class property "' . $index . '" does not exists'
205
                );
206
            }
207
            $this->index = $index;
208
209
            return $this;
210
        }
211
212
        if (array_key_exists($index, $this->datas)) {
213
            $this->value = $this->datas[$index];
214
            $this->index = $index;
215
216
            return $this;
217
        }
218
219
        throw new InvalidArgumentException(
220
            'Index / Property "' . $index . '" does not exists'
221
        );
222
    }
223
224
    public function callValidate()
225
    {
226
        $args = func_get_args();
227
        if (count($args) < 1) {
228
            throw new InvalidArgumentException('bad number of arguments');
229
        }
230
231
        $method = array_shift($args);
232
        if (is_callable($method)) {
233
            $this->index = null;
234
            $this->value = call_user_func_array($method, $args);
235
236
            return $this;
237
        }
238
239
        throw new InvalidArgumentException('Bad method');
240
    }
241
242 15
    public function __call($method, $parameters)
243
    {
244 15
        if (!$this->stop) {
245
            // Stop on error, ignore others tests if fails
246 15
            if (substr($method, 0, 4) == 'stop') {
247
                $stopOnError = true;
248
                $method = lcFirst(substr($method, 4));
249
            } else {
250 15
                $stopOnError = false;
251
            }
252
253
            // Negation check
254 15
            if (substr(strtolower($method), 0, 3) == 'not') {
255
                $negation = true;
256
                $method = lcFirst(substr($method, 3));
257
            } else {
258 15
                $negation = false;
259
            }
260
261 15
            if (!isset($this->checks[$method])) {
262
                throw new BadMethodCallException('Unknown check ' . $method);
263
            } else {
264 15
                $validator = $this->checks[$method];
265
            }
266
267 15
            $errorMessage = array_pop($parameters);
268
269 15
            array_unshift($parameters, $this->value);
270
271 15
            $validation = (bool) (call_user_func_array(
272 15
                $validator,
273
                $parameters
274 15
            ) ^ $negation);
275 15
            if (!$validation) {
276 9
                if ($stopOnError) {
277
                    $this->stop = true;
278
                }
279 9
                if ($this->index === null) {
280 9
                    $this->errors[] = $errorMessage;
281
                } else {
282
                    $this->errors[$this->index][] = $errorMessage;
283
                }
284
            }
285
        }
286
287 15
        return $this;
288
    }
289
290 2
    public function getErrors($index = null)
291
    {
292 2
        if ($index === null) {
293 2
            return $this->errors;
294
        } else {
295
            return isset($this->errors[$index]) ? $this->errors[$index] : [];
296
        }
297
    }
298
299 15
    public function pass()
300
    {
301 15
        return count($this->errors) == 0;
302
    }
303
304 8
    public function fails()
305
    {
306 8
        return !$this->pass();
307
    }
308
}
309