Passed
Push — master ( 808208...9d534e )
by Runner
01:56
created

Validator::createMessageTemplates()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 4
nop 1
crap 3
1
<?php
2
/**
3
 * @author: RunnerLee
4
 * @email: [email protected]
5
 * @time: 17-2-20 15:22
6
 */
7
8
namespace Runner\Validator;
9
10
use Closure;
11
12
/**
13
 * Class Validator.
14
 */
15
class Validator
16
{
17
    /**
18
     * @var array
19
     */
20
    protected $data = [];
21
22
    /**
23
     * @var array
24
     */
25
    protected $ruleGroups = [];
26
27
    /**
28
     * @var array
29
     */
30
    protected $messages = [];
31
32
    /**
33
     * @var array
34
     */
35
    protected static $forceRules = ['Required', 'RequiredIf', 'RequiredWith', 'RequiredUnless', 'RequiredWithout'];
36
37
    /**
38
     * @var array
39
     */
40
    protected $messageTemplates = [];
41
42
    /**
43
     * @var array
44
     */
45
    protected static $extensions = [];
46
47
    /**
48
     * @var array
49
     */
50
    protected static $extensionMessageTemplates = [];
51
52
    /**
53
     * @var array
54
     */
55
    protected static $initialMessageTemplates = [];
56
57
    /**
58
     * Validator constructor.
59
     *
60
     * @param array $data
61
     * @param array $ruleGroups
62
     * @param array $messageTemplates
63
     */
64 6
    public function __construct(array $data, array $ruleGroups, array $messageTemplates = [])
65
    {
66 6
        $this->data = $data;
67 6
        $this->parseRules($ruleGroups);
68 6
        $this->createMessageTemplates($messageTemplates);
69 6
    }
70
71
    /**
72
     * @param $name
73
     * @param $callback
74
     * @param bool   $isForce
75
     * @param string $message
76
     */
77 3
    public static function addExtension($name, $callback, $isForce = false, $message = null)
78
    {
79 3
        $name = self::formatRuleName($name);
80
81 3
        self::$extensions[$name] = $callback;
82
83 3
        $isForce && self::$forceRules[] = $name;
84
85 3
        !empty($message) && (static::$extensionMessageTemplates[$name] = $message);
86 3
    }
87
88
    /**
89
     * @return bool
90
     */
91 5
    public function validate()
92
    {
93 5
        foreach ($this->ruleGroups as $field => $rules) {
94 5
            if ($this->hasField($field)) {
95 5
                $value = $this->getField($field);
96 5
                foreach ($rules as $rule => $parameters) {
97 5
                    if (!$this->runValidateRule($field, $value, $rule, $parameters)) {
98 5
                        $this->messages[$field][$rule] = $this->buildFailMessage($rule, $field, $parameters);
99
                    }
100
                }
101 1
            } elseif ($forceRules = array_intersect(self::$forceRules, array_keys($rules))) {
102 1
                $value = null;
103 1
                foreach ($forceRules as $rule) {
104 1
                    if (!$this->runValidateRule($field, null, $rule, $rules[$rule])) {
105 5
                        $this->messages[$field][$rule] = $this->buildFailMessage($rule, $field, $rules[$rule]);
106
                    }
107
                }
108
            }
109
        }
110
111 5
        return 0 === count($this->messages);
112
    }
113
114
    /**
115
     * @return array
116
     */
117 1
    public function fails()
118
    {
119 1
        return array_keys($this->messages);
120
    }
121
122
    /**
123
     * @return array
124
     */
125 2
    public function messages()
126
    {
127 2
        return $this->messages;
128
    }
129
130
    /**
131
     * @return array
132
     */
133 1
    public function data()
134
    {
135 1
        return $this->data;
136
    }
137
138
    /**
139
     * @param array $messages
140
     */
141 6
    protected function createMessageTemplates(array $messages = [])
142
    {
143 6
        if (empty(self::$initialMessageTemplates)) {
144 1
            self::$initialMessageTemplates = require __DIR__ . '/message.php';
145
        }
146
147 6
        $this->messageTemplates = array_merge(self::$initialMessageTemplates, self::$extensionMessageTemplates);
148
149 6
        foreach ($messages as $rule => $message) {
150 1
            $this->messageTemplates[self::formatRuleName($rule)] = $message;
151
        }
152 6
    }
153
154
    /**
155
     * @param array $ruleGroups
156
     */
157 6
    protected function parseRules(array $ruleGroups)
158
    {
159 6
        $map = [];
160 6
        foreach ($ruleGroups as $field => $rules) {
161 5
            foreach (explode('|', $rules) as $rule) {
162 5
                list($rule, $parameters) = explode(':', (false === strpos($rule, ':') ? ($rule.':') : $rule), 2);
163 5
                !isset($map[$rule]) && $map[$rule] = self::formatRuleName($rule);
164 5
                $rule = $map[$rule];
165 5
                $this->ruleGroups[$field][$rule] = ('' === $parameters ? [] : explode(',', $parameters));
166
            }
167
        }
168 6
        unset($map);
169 6
    }
170
171
    /**
172
     * @param $name
173
     *
174
     * @return string
175
     */
176 5
    protected static function formatRuleName($name)
177
    {
178 5
        return implode(
179 5
            '',
180 5
            array_map(
181 5
                function ($value) {
182 5
                    return ucfirst($value);
183 5
                },
184 5
                explode('_', $name)
185
            )
186
        );
187
    }
188
189
    /**
190
     * @param string $field
191
     *
192
     * @return bool
193
     */
194 5
    protected function hasField($field)
195
    {
196 5
        $field = explode('.', $field);
197 5
        $item = array_shift($field);
198 5
        if (!array_key_exists($item, $this->data)) {
199 1
            return false;
200
        }
201 5
        $value = $this->data[$item];
202
203 5
        foreach ($field as $item) {
204 1
            if (!array_key_exists($item, $value)) {
205 1
                return false;
206
            }
207 1
            $value = $value[$item];
208
        }
209
210 5
        return true;
211
    }
212
213
    /**
214
     * @param string $field
215
     *
216
     * @return mixed
217
     */
218 5
    protected function getField($field)
219
    {
220 5
        $field = explode('.', $field);
221 5
        $item = array_shift($field);
222 5
        $value = $this->data[$item];
223 5
        foreach ($field as $item) {
224 1
            $value = $value[$item];
225
        }
226
227 5
        return $value;
228
    }
229
230
    /**
231
     * @param $field
232
     * @param $value
233
     * @param $rule
234
     * @param array $parameters
235
     *
236
     * @return bool
237
     */
238 5
    protected function runValidateRule($field, $value, $rule, array $parameters = [])
239
    {
240 5
        if (array_key_exists($rule, self::$extensions)) {
241 3
            $callback = self::$extensions[$rule];
242 3
            if ($callback instanceof Closure) {
243 3
                $callback = $callback->bindTo($this, $this);
244
            }
245
246 3
            return (bool) call_user_func($callback, $field, $value, $parameters);
247
        }
248
249 4
        return (bool) call_user_func([$this, "validate{$rule}"], $field, $value, $parameters);
250
    }
251
252
    /**
253
     * @param $rule
254
     * @param $field
255
     * @param array $parameters
256
     *
257
     * @return string
258
     */
259 3
    protected function buildFailMessage($rule, $field, array $parameters = [])
260
    {
261 3
        if (!isset($this->messageTemplates[$rule])) {
262 1
            return "{$field} field check failed";
263
        }
264 3
        array_unshift($parameters, "{$field} {$this->messageTemplates[$rule]}");
265
266
        try {
267 3
            return call_user_func_array('sprintf', $parameters);
268 1
        } catch (\Exception $e) {
269 1
            return "{$field} filed check failed";
270
        }
271
    }
272
273
    /**
274
     * @param $field
275
     * @param $value
276
     * @param array $parameters
277
     *
278
     * @return bool
279
     */
280 1
    protected function validateAccept($field, $value, array $parameters = [])
281
    {
282 1
        return in_array(strtolower($value), ['yes', 'on', '1', 1, true], true);
283
    }
284
285
    /**
286
     * @param $field
287
     * @param $value
288
     * @param array $parameters
289
     *
290
     * @return bool
291
     */
292 1
    protected function validateNumeric($field, $value, array $parameters = [])
293
    {
294 1
        return false !== filter_var($value, FILTER_VALIDATE_INT) || false !== filter_var($value, FILTER_VALIDATE_FLOAT);
295
    }
296
297
    /**
298
     * @param $field
299
     * @param $value
300
     * @param array $parameters
301
     *
302
     * @return bool
303
     */
304 2
    protected function validateInteger($field, $value, array $parameters = [])
305
    {
306 2
        return false !== filter_var($value, FILTER_VALIDATE_INT);
307
    }
308
309
    /**
310
     * @param $field
311
     * @param $value
312
     * @param array $parameters
313
     *
314
     * @return bool
315
     */
316 1
    protected function validateFloat($field, $value, array $parameters = [])
317
    {
318 1
        return false !== filter_var($value, FILTER_VALIDATE_FLOAT);
319
    }
320
321
    /**
322
     * @param $field
323
     * @param $value
324
     * @param array $parameters
325
     *
326
     * @return bool
327
     */
328 4
    protected function validateSize($field, $value, array $parameters)
329
    {
330 4
        $size = filter_var($parameters[0], FILTER_VALIDATE_INT);
331 4
        false === $size && $size = filter_var($parameters[0], FILTER_VALIDATE_FLOAT);
332
333 4
        return $this->getSize($field, $value) === $size;
334
    }
335
336
    /**
337
     * @param $field
338
     * @param $value
339
     * @param array $parameters
340
     *
341
     * @return bool
342
     */
343 1
    protected function validateUrl($field, $value, array $parameters = [])
344
    {
345 1
        return false !== filter_var($value, FILTER_VALIDATE_URL);
346
    }
347
348
    /**
349
     * @param $field
350
     * @param $value
351
     * @param array $parameters
352
     *
353
     * @return bool
354
     */
355 1
    protected function validateBoolean($field, $value, array $parameters = [])
356
    {
357 1
        return in_array($value, [true, false, 0, 1, '0', '1'], true);
358
    }
359
360
    /**
361
     * @param $field
362
     * @param $value
363
     * @param array $parameters
364
     *
365
     * @return bool
366
     */
367 1
    protected function validateConfirm($field, $value, array $parameters)
368
    {
369 1
        return $value === $this->data[$parameters[0]];
370
    }
371
372
    /**
373
     * @param $field
374
     * @param $value
375
     * @param array $parameters
376
     *
377
     * @return bool
378
     */
379 1
    protected function validateDate($field, $value, array $parameters = [])
380
    {
381 1
        return false !== strtotime($value);
382
    }
383
384
    /**
385
     * 邮箱地址
386
     *
387
     * @param $field
388
     * @param $value
389
     * @param array $parameters
390
     *
391
     * @return bool
392
     */
393 1
    protected function validateEmail($field, $value, array $parameters = [])
394
    {
395 1
        return false !== filter_var($value, FILTER_VALIDATE_EMAIL);
396
    }
397
398
    /**
399
     * @param $field
400
     * @param $value
401
     * @param array $parameters
402
     *
403
     * @return bool
404
     */
405 1
    protected function validateRequired($field, $value, array $parameters = [])
406
    {
407 1
        return !is_null($value);
408
    }
409
410
    /**
411
     * @param $field
412
     * @param $value
413
     * @param array $parameters
414
     *
415
     * @return bool
416
     */
417 1
    protected function validateRequiredWith($field, $value, array $parameters)
418
    {
419 1
        return !is_null($value) || !array_key_exists($parameters[0], $this->data);
420
    }
421
422
    /**
423
     * @param $field
424
     * @param $value
425
     * @param array $parameters
426
     *
427
     * @return bool
428
     */
429 1
    protected function validateRequiredWithout($field, $value, array $parameters)
430
    {
431 1
        return !is_null($value) || array_key_exists($parameters[0], $this->data);
432
    }
433
434
    /**
435
     * @param $field
436
     * @param $value
437
     * @param array $parameters
438
     *
439
     * @return bool
440
     */
441 1
    protected function validateRequiredIf($field, $value, array $parameters)
442
    {
443 1
        $otherField = array_shift($parameters);
444
445 1
        return !is_null($value) || (
446 1
            !array_key_exists($otherField, $this->data) || false === array_search($this->data[$otherField], $parameters)
447
        );
448
    }
449
450
    /**
451
     * @param $field
452
     * @param $value
453
     * @param array $parameters
454
     *
455
     * @return bool
456
     */
457 1
    protected function validateRequiredUnless($field, $value, array $parameters)
458
    {
459 1
        $otherField = array_shift($parameters);
460
461 1
        return !is_null($value) || (
462 1
            !array_key_exists($otherField, $this->data) || false !== array_search($this->data[$otherField], $parameters)
463
        );
464
    }
465
466
    /**
467
     * @param $field
468
     * @param $value
469
     * @param array $parameters
470
     *
471
     * @return bool
472
     */
473 1
    protected function validateArray($field, $value, array $parameters = [])
474
    {
475 1
        return is_array($value);
476
    }
477
478
    /**
479
     * @param $field
480
     * @param $value
481
     * @param array $parameteres
482
     *
483
     * @return bool
484
     */
485 1
    protected function validateString($field, $value, array $parameteres = [])
486
    {
487 1
        return is_string($value);
488
    }
489
490
    /**
491
     * @param $field
492
     * @param $value
493
     * @param array $parameters
494
     *
495
     * @return bool
496
     */
497 1
    protected function validateNullable($field, $value, array $parameters = [])
498
    {
499 1
        return true;
500
    }
501
502
    /**
503
     * @param $field
504
     * @param $value
505
     * @param array $parameters
506
     *
507
     * @return bool
508
     */
509 1
    protected function validateMin($field, $value, array $parameters)
510
    {
511 1
        return $this->getSize($field, $value) >= $parameters[0];
512
    }
513
514
    /**
515
     * @param $field
516
     * @param $value
517
     * @param array $parameters
518
     *
519
     * @return bool
520
     */
521 1
    protected function validateMax($field, $value, array $parameters)
522
    {
523 1
        return $this->getSize($field, $value) <= $parameters[0];
524
    }
525
526
    /**
527
     * @param $field
528
     * @param $value
529
     * @param array $parameters
530
     *
531
     * @return bool
532
     */
533 1
    protected function validateRange($field, $value, array $parameters)
534
    {
535 1
        $size = $this->getSize($field, $value);
536 1
        if (!isset($parameters[0])) {
537 1
            return false;
538
        }
539 1
        if (isset($parameters[1])) {
540 1
            if ('' === $parameters[0]) {
541 1
                if ('' === $parameters[1]) {
542 1
                    return false;
543
                }
544
545 1
                return $size <= $parameters[1];
546
            }
547 1
            if ('' === $parameters[1]) {
548 1
                return $size >= $parameters[0];
549
            }
550
551 1
            return $size >= $parameters[0] && $size <= $parameters[1];
552
        }
553
554 1
        return '' === $parameters[0] ? false : ($size >= $parameters[0]);
555
    }
556
557
    /**
558
     * @param $field
559
     * @param $value
560
     * @param array $parameters
561
     *
562
     * @return bool
563
     */
564 1
    protected function validateRegex($field, $value, array $parameters)
565
    {
566 1
        return (bool) preg_match($parameters[0], $value);
567
    }
568
569
    /**
570
     * @param $field
571
     * @param $value
572
     * @param array $parameters
573
     *
574
     * @return bool
575
     */
576 1
    protected function validateIn($field, $value, array $parameters)
577
    {
578 1
        return in_array($value, $parameters, true);
579
    }
580
581
    /**
582
     * @param $field
583
     * @param $value
584
     * @param array $parameters
585
     *
586
     * @return bool
587
     */
588 1
    protected function validateIp($field, $value, array $parameters = [])
589
    {
590 1
        return false !== filter_var($value, FILTER_VALIDATE_IP);
591
    }
592
593
    /**
594
     * @param $field
595
     * @param $value
596
     * @param array $parameters
597
     *
598
     * @return bool
599
     */
600 1
    protected function validateDateFormat($field, $value, array $parameters)
601
    {
602 1
        return !(bool) date_parse_from_format($parameters[0], $value)['error_count'];
603
    }
604
605
    /**
606
     * @param $field
607
     * @param $value
608
     * @param array $parameters
609
     *
610
     * @return bool
611
     */
612 1
    protected function validateDateBefore($field, $value, array $parameters)
613
    {
614 1
        return strtotime($value) < strtotime($parameters[0]);
615
    }
616
617
    /**
618
     * @param $field
619
     * @param $value
620
     * @param array $parameters
621
     *
622
     * @return bool
623
     */
624 1
    protected function validateDateAfter($field, $value, array $parameters)
625
    {
626 1
        return strtotime($value) > strtotime($parameters[0]);
627
    }
628
629
    /**
630
     * @param $field
631
     * @param $value
632
     * @param array $parameters
633
     *
634
     * @return bool
635
     */
636 1
    protected function validateJson($field, $value, array $parameters)
637
    {
638 1
        return is_array(json_decode($value, true));
639
    }
640
641
    /**
642
     * @param $field
643
     * @param $value
644
     * @param array $parameters
645
     *
646
     * @return bool
647
     */
648 1
    protected function validateDiff($field, $value, array $parameters)
649
    {
650 1
        $specifyField = array_shift($parameters);
651
652 1
        return array_key_exists($specifyField, $this->data) && $value !== $this->data[$specifyField];
653
    }
654
655
    /**
656
     * @param $field
657
     * @param $value
658
     *
659
     * @return int|float
660
     */
661 4
    protected function getSize($field, $value)
662
    {
663
        switch (true) {
664 4
            case isset($this->ruleGroups[$field]['String']) && is_string($value):
665 1
                return strlen($value);
666 4
            case is_array($value):
667 1
                return count($value);
668 4
            case false !== $temp = filter_var($value, FILTER_VALIDATE_INT):
669 2
                return $temp;
670 4
            case false !== $temp = filter_var($value, FILTER_VALIDATE_FLOAT):
671 1
                return $temp;
672
            default:
673 4
                return mb_strlen($value);
674
        }
675
    }
676
}
677