Completed
Push — master ( 119440...87e4b9 )
by Peter
16:02
created

Validator::getErrors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * This software package is licensed under AGPL or Commercial license.
5
 *
6
 * @package maslosoft/mangan
7
 * @licence AGPL or Commercial
8
 * @copyright Copyright (c) Piotr Masełkowski <[email protected]>
9
 * @copyright Copyright (c) Maslosoft
10
 * @copyright Copyright (c) Others as mentioned in code
11
 * @link http://maslosoft.com/mangan/
12
 */
13
14
namespace Maslosoft\Mangan;
15
16
use InvalidArgumentException;
17
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
18
use Maslosoft\Mangan\Helpers\Validator\Factory;
19
use Maslosoft\Mangan\Interfaces\ValidatableInterface;
20
use Maslosoft\Mangan\Meta\ManganMeta;
21
22
/**
23
 * Validator
24
 *
25
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
26
 */
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 100
	public function __construct(AnnotatedInterface $model)
53
	{
54 100
		$this->model = $model;
55 100
		$this->meta = ManganMeta::create($this->model);
56
57
		// Ensure that errors array is initialized - even if does not have validators
58 100
		foreach (array_keys($this->meta->fields()) as $name)
59
		{
60 100
			$this->errors[$name] = [];
61 100
		}
62 100
	}
63
64
	/**
65
	 * Validate model, optionally only selected fields
66
	 * @param string[] $fields
67
	 * @return boolean
68
	 */
69 72
	public function validate($fields = [])
70
	{
71 72
		$valid = [];
72 72
		if (empty($fields))
73 72
		{
74 72
			$fields = array_keys($this->meta->fields());
75 72
		}
76 72
		foreach ($fields as $name)
77
		{
78 72
			$fieldMeta = $this->meta->field($name);
79
80
			// Reset errors
81 72
			$this->errors[$name] = [];
82
83
			// Check if meta for field exists
84 72
			if (empty($fieldMeta))
85 72
			{
86
				throw new InvalidArgumentException(sprintf("Unknown field `%s` in model `%s`", $name, get_class($this->model)));
87
			}
88
89
			// Validate sub documents
90 72
			if ($fieldMeta->owned)
91 72
			{
92 21
				if (is_array($this->model->$name))
93 21
				{
94 10
					foreach ($this->model->$name as $model)
95
					{
96 10
						$validator = new Validator($model);
97 10
						$valid[] = (int) $validator->validate();
98 10
					}
99 10
				}
100 15
				elseif (!empty($this->model->$name))
101
				{
102 15
					$validator = new Validator($this->model->$name);
103 15
					$valid[] = (int) $validator->validate();
104 15
				}
105 21
			}
106
107
			// Skip field without validators
108 72
			if (empty($fieldMeta->validators))
109 72
			{
110 71
				continue;
111
			}
112 16
			$valid[] = (int) $this->validateEntity($name, $fieldMeta->validators);
113 72
		}
114
		
115
		// Model validators
116 72
		$typeValidators = $this->meta->type()->validators;
117 72
		if(!empty($typeValidators))
118 72
		{
119 1
			$typeName = $this->meta->type()->name;
120
			// Reset errors
121 1
			$this->errors[$typeName] = [];
122 1
			$valid[] = (int) $this->validateEntity($typeName, $typeValidators);
123 1
		}
124 72
		return count($valid) === array_sum($valid);
125
	}
126
127 17
	private function validateEntity($name, $validators)
128
	{
129 17
		$valid = [];
130 17
		foreach ($validators as $validatorMeta)
131
		{
132
			// Filter out validators based on scenarios
133 17
			if (!empty($validatorMeta->on))
134 17
			{
135 2
				$on = (array) $validatorMeta->on;
136 2
				$enabled = false;
137 2
				foreach ($on as $scenario)
138
				{
139 2
					if ($scenario === ScenarioManager::getScenario($this->model))
140 2
					{
141 2
						$enabled = true;
142 2
						break;
143
					}
144 2
				}
145 2
				if (!$enabled)
146 2
				{
147 2
					continue;
148
				}
149 2
			}
150 17
			if (!empty($validatorMeta->except))
151 17
			{
152 1
				$except = (array) $validatorMeta->except;
153 1
				$enabled = true;
154 1
				foreach ($except as $scenario)
155
				{
156 1
					if ($scenario === ScenarioManager::getScenario($this->model))
157 1
					{
158 1
						$enabled = false;
159 1
						break;
160
					}
161 1
				}
162 1
				if (!$enabled)
163 1
				{
164 1
					continue;
165
				}
166 1
			}
167
168
169
			// Create validator and validate
170 17
			$validator = Factory::create($this->model, $validatorMeta, $name);
171 17
			if ($validator->isValid($this->model, $name))
172 17
			{
173 13
				$valid[] = true;
174 13
			}
175
			else
176
			{
177 17
				$valid[] = false;
178 17
				$this->errors[$name] = array_merge($this->errors[$name], $validator->getErrors());
179
180
				// Set errors to model instance if it implements ValidatableInterface
181 17
				if ($this->model instanceof ValidatableInterface)
182 17
				{
183 3
					$this->model->setErrors($this->errors);
184 3
				}
185
			}
186 17
		}
187 17
		return count($valid) === array_sum($valid);
188
	}
189
190 1
	public function getErrors()
191
	{
192 1
		return $this->errors;
193
	}
194
195 3
	public function setErrors($errors)
196
	{
197 3
		foreach ($errors as $field => $errors)
198
		{
199 3
			$this->errors[$field] = $errors;
200 3
		}
201 3
	}
202
203
}
204