Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
41 / 41 |
|
100.00% |
7 / 7 |
CRAP | |
100.00% |
1 / 1 |
Validator | |
100.00% |
41 / 41 |
|
100.00% |
7 / 7 |
17 | |
100.00% |
1 / 1 |
validate | |
100.00% |
29 / 29 |
|
100.00% |
1 / 1 |
11 | |||
map | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
mapBack | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getData | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getErrors | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addErrors | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
configureValidationFactory | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace Engelsystem\Http\Validation; |
6 | |
7 | use Illuminate\Support\Str; |
8 | use InvalidArgumentException; |
9 | use ReflectionProperty; |
10 | use Respect\Validation\Exceptions\ComponentException; |
11 | use Respect\Validation\Factory; |
12 | use Respect\Validation\Validator as RespectValidator; |
13 | |
14 | class Validator |
15 | { |
16 | /** @var string[] */ |
17 | protected array $errors = []; |
18 | |
19 | protected array $data = []; |
20 | |
21 | protected array $mapping = [ |
22 | 'accepted' => 'Checked', |
23 | 'int' => 'IntVal', |
24 | 'float' => 'FloatVal', |
25 | 'required' => 'NotEmpty', |
26 | 'optional' => 'nullable', |
27 | ]; |
28 | |
29 | public function validate(array $data, array $rules): bool |
30 | { |
31 | $this->errors = []; |
32 | $this->data = []; |
33 | |
34 | $this->configureValidationFactory(); |
35 | |
36 | $validData = []; |
37 | foreach ($rules as $fieldName => $rulesList) { |
38 | $value = $data[$fieldName] ?? null; |
39 | $rulesList = is_array($rulesList) ? $rulesList : explode('|', $rulesList); |
40 | |
41 | // Configure the check to be run for every rule |
42 | foreach ($rulesList as $parameters) { |
43 | $v = new RespectValidator(); |
44 | |
45 | $parameters = is_array($parameters) ? $parameters : explode(':', $parameters); |
46 | $rule = array_shift($parameters); |
47 | $rule = Str::camel($rule); |
48 | $rule = $this->map($rule); |
49 | |
50 | // Handle empty/optional values |
51 | if ($rule == 'nullable') { |
52 | if (is_null($value) || $value === '') { |
53 | $validData[$fieldName] = null; |
54 | break; |
55 | } |
56 | |
57 | $validData[$fieldName] = $value; |
58 | continue; |
59 | } |
60 | |
61 | // Configure the validation |
62 | try { |
63 | $v = call_user_func_array([$v, $rule], $parameters); |
64 | } catch (ComponentException $e) { |
65 | throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); |
66 | } |
67 | |
68 | // Run validation |
69 | if ($v->validate($value)) { |
70 | $validData[$fieldName] = $value; |
71 | } else { |
72 | $this->errors[$fieldName][] = implode('.', ['validation', $fieldName, $this->mapBack($rule)]); |
73 | } |
74 | } |
75 | } |
76 | |
77 | $success = empty($this->errors); |
78 | if ($success) { |
79 | $this->data = $validData; |
80 | } |
81 | |
82 | return $success; |
83 | } |
84 | |
85 | protected function map(string $rule): string |
86 | { |
87 | return $this->mapping[$rule] ?? $rule; |
88 | } |
89 | |
90 | protected function mapBack(string $rule): string |
91 | { |
92 | $mapping = array_flip($this->mapping); |
93 | |
94 | return $mapping[$rule] ?? $rule; |
95 | } |
96 | |
97 | public function getData(): array |
98 | { |
99 | return $this->data; |
100 | } |
101 | |
102 | /** |
103 | * @return string[] |
104 | */ |
105 | public function getErrors(): array |
106 | { |
107 | return $this->errors; |
108 | } |
109 | |
110 | public function addErrors(array $errors): self |
111 | { |
112 | $this->errors = array_merge($this->errors, $errors); |
113 | |
114 | return $this; |
115 | } |
116 | |
117 | protected function configureValidationFactory(): void |
118 | { |
119 | $f = (new Factory()) |
120 | ->withRuleNamespace('\\Engelsystem\\Http\\Validation\\Rules'); |
121 | |
122 | // Hacking around, alternative is to reimplement it... |
123 | $property = new ReflectionProperty($f, 'rulesNamespaces'); |
124 | $property->setValue($f, array_reverse($property->getValue($f))); |
125 | |
126 | Factory::setDefaultInstance($f); |
127 | } |
128 | } |