1 | <?php |
||
27 | class Validator implements ValidatableInterface |
||
28 | { |
||
29 | |||
30 | const EventBeforeValidate = 'beforeValidate'; |
||
31 | const EventAfterValidate = 'afterValidate'; |
||
32 | |||
33 | /** |
||
34 | * Model instance |
||
35 | * @var AnnotatedInterface |
||
36 | */ |
||
37 | private $model = null; |
||
38 | |||
39 | /** |
||
40 | * Metadata for model |
||
41 | * @var ManganMeta |
||
42 | */ |
||
43 | private $meta = null; |
||
44 | |||
45 | /** |
||
46 | * Array of error messages. |
||
47 | * Keys are field names, secondary keys are numeric |
||
48 | * @var string[][] |
||
49 | */ |
||
50 | private $errors = []; |
||
51 | |||
52 | 112 | public function __construct(AnnotatedInterface $model) |
|
63 | |||
64 | /** |
||
65 | * Validate model, optionally only selected fields |
||
66 | * @param string[] $fields |
||
67 | * @return boolean |
||
68 | */ |
||
69 | 79 | public function validate($fields = []) |
|
70 | { |
||
71 | 79 | $valid = []; |
|
72 | 79 | if (empty($fields)) |
|
73 | { |
||
74 | 79 | $fields = array_keys($this->meta->fields()); |
|
75 | } |
||
76 | 79 | foreach ($fields as $name) |
|
77 | { |
||
78 | 79 | $fieldMeta = $this->meta->field($name); |
|
79 | |||
80 | // Reset errors |
||
81 | 79 | $this->errors[$name] = []; |
|
82 | |||
83 | // Check if meta for field exists |
||
84 | 79 | if (empty($fieldMeta)) |
|
85 | { |
||
86 | throw new InvalidArgumentException(sprintf("Unknown field `%s` in model `%s`", $name, get_class($this->model))); |
||
87 | } |
||
88 | |||
89 | // Validate sub documents |
||
90 | // Skip fields that are not updatable |
||
91 | 79 | if ($fieldMeta->owned && $fieldMeta->updatable) |
|
92 | { |
||
93 | 26 | if (is_array($this->model->$name)) |
|
94 | { |
||
95 | // Handle arrays of documents |
||
96 | 11 | foreach ($this->model->$name as $fieldIndex => $model) |
|
97 | { |
||
98 | 11 | $validator = new Validator($model); |
|
99 | 11 | $isValid = $validator->validate(); |
|
100 | 11 | $valid[] = (int) $isValid; |
|
101 | 11 | if (!$isValid) |
|
102 | { |
||
103 | $errors = [ |
||
104 | $name => [ |
||
105 | 3 | $fieldIndex => $validator->getErrors() |
|
106 | ] |
||
107 | ]; |
||
108 | 11 | $this->setErrors($errors); |
|
109 | } |
||
110 | } |
||
111 | } |
||
112 | elseif (!empty($this->model->$name)) |
||
113 | { |
||
114 | // Handle single documents |
||
115 | 19 | $validator = new Validator($this->model->$name); |
|
116 | 19 | $isValid = $validator->validate(); |
|
117 | 19 | $valid[] = (int) $isValid; |
|
118 | 19 | if (!$isValid) |
|
119 | { |
||
120 | $errors = [ |
||
121 | 3 | $name => $validator->getErrors() |
|
122 | ]; |
||
123 | 3 | $this->setErrors($errors); |
|
124 | } |
||
125 | } |
||
126 | } |
||
127 | |||
128 | // Skip field without validators |
||
129 | 79 | if (empty($fieldMeta->validators)) |
|
130 | { |
||
131 | 78 | continue; |
|
132 | } |
||
133 | 18 | $valid[] = (int) $this->validateEntity($name, $fieldMeta->validators); |
|
134 | } |
||
135 | |||
136 | // Model validators |
||
137 | 79 | $typeValidators = $this->meta->type()->validators; |
|
138 | 79 | if (!empty($typeValidators)) |
|
139 | { |
||
140 | 1 | $typeName = $this->meta->type()->name; |
|
141 | // Reset errors |
||
142 | 1 | $this->errors[$typeName] = []; |
|
143 | 1 | $valid[] = (int) $this->validateEntity($typeName, $typeValidators); |
|
144 | } |
||
145 | 79 | return count($valid) === array_sum($valid); |
|
146 | } |
||
147 | |||
148 | 19 | private function validateEntity($name, $validators) |
|
210 | |||
211 | 8 | public function getErrors() |
|
215 | |||
216 | 9 | public function setErrors($errors) |
|
223 | |||
224 | } |
||
225 |