1 | <?php |
||
10 | final class ArrayValidator implements ValidatorInterface |
||
11 | { |
||
12 | /** |
||
13 | * @var array<string, ValidatorInterface> |
||
14 | */ |
||
15 | private array $validators; |
||
|
|||
16 | private bool $ignoreUnknown; |
||
17 | |||
18 | /** |
||
19 | * @param array<string, ValidatorInterface> $validators |
||
20 | */ |
||
21 | public function __construct(array $validators = [], bool $ignoreUnknown = false) |
||
22 | { |
||
23 | $this->validators = $validators; |
||
24 | $this->ignoreUnknown = $ignoreUnknown; |
||
25 | } |
||
26 | |||
27 | /** |
||
28 | * Create a new validator flagged if unknown items should be ignored when validating |
||
29 | */ |
||
30 | public function ignoreUnknown(bool $ignoreUnknown = true): ArrayValidator |
||
31 | { |
||
32 | return new static($this->validators, $ignoreUnknown); |
||
33 | } |
||
34 | |||
35 | public function applyTo($data): ResultInterface |
||
36 | { |
||
37 | if (!is_array($data)) { |
||
38 | return new Invalid(new Exception("expecting array input")); |
||
39 | } |
||
40 | |||
41 | /** @var array<string, mixed> */ |
||
42 | $clean = []; |
||
43 | |||
44 | /** @var array<string, string> */ |
||
45 | $errors = []; |
||
46 | |||
47 | foreach ($this->validators as $name => $validator) { |
||
48 | $result = $validator->applyTo($data[$name] ?? null); |
||
49 | |||
50 | if ($result->isValid()) { |
||
51 | $clean[$name] = $result->getValidData(); |
||
52 | continue; |
||
53 | } |
||
54 | |||
55 | $errors[$name] = implode("\n", $result->getErrors()); |
||
56 | } |
||
57 | |||
58 | if (!$this->ignoreUnknown && $diff = array_diff_key($data, $this->validators)) { |
||
59 | foreach (array_keys($diff) as $unknown) { |
||
60 | $errors[(string)$unknown] = "Unknown input item $unknown"; |
||
61 | } |
||
62 | } |
||
63 | |||
64 | return new ArrayResult($clean, $errors); |
||
65 | } |
||
66 | |||
67 | public function validate($data) |
||
68 | { |
||
69 | $result = $this->applyTo($data); |
||
70 | |||
71 | if ($result->isValid()) { |
||
72 | return $result->getValidData(); |
||
73 | } |
||
74 | |||
75 | $msg = ''; |
||
76 | |||
77 | foreach ($result->getErrors() as $name => $error) { |
||
78 | $msg .= "$name: $error\n"; |
||
79 | } |
||
80 | |||
81 | throw new Exception(trim($msg)); |
||
82 | } |
||
83 | } |
||
84 |