Test Failed
Push — master ( 56388c...2301f2 )
by Jan
02:10
created

Validator::handle()   B

Complexity

Conditions 7
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 9
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 17
rs 8.8333

1 Method

Rating   Name   Duplication   Size   Complexity  
A Validator::getErrorsList() 0 3 1
1
<?php
2
3
namespace Kontrolio;
4
5
use Kontrolio\Data\Data;
6
use Kontrolio\Error\Errors;
7
use Kontrolio\Rules\Core\UntilFirstFailure;
8
use Kontrolio\Rules\ArrayNormalizer;
9
use Kontrolio\Rules\Instantiator;
10
use Kontrolio\Rules\StopsFurtherValidationInterface;
11
use Kontrolio\Rules\Parser;
12
use Kontrolio\Rules\Repository;
13
use Kontrolio\Rules\CallableRuleWrapper;
14
use UnexpectedValueException;
15
16
/**
17
 * Main class of the validation service.
18
 *
19
 * @package Kontrolio
20
 */
21
class Validator implements ValidatorInterface
22
{
23
    /**
24
     * Data to validate.
25
     *
26
     * @var Data
27
     */
28
    private $data;
29
    
30
    /**
31
     * Raw validation rules.
32
     *
33
     * @var array
34
     */
35
    private $rules;
36
37
    /**
38
     * Formatted validation rules.
39
     *
40
     * @var array
41
     */
42
    private $normalizedRules = [];
43
44
    /**
45
     * Validation messages.
46
     *
47
     * @var array
48
     */
49
    private $messages;
50
51
    /**
52
     * Available validation rules.
53
     *
54
     * @var Repository
55
     */
56
    private $repository;
57
58
    /**
59
     * Raw rules normalizer.
60
     *
61
     * @var ArrayNormalizer
62
     */
63
    private $normalizer;
64
65
    /**
66
     * Validation errors.
67
     *
68
     * @var Errors
69
     */
70
    private $errors;
71
72
    /**
73
     * Flag indicating that the validation should stop.
74
     *
75
     * @var bool
76
     */
77
    private $shouldStopOnFirstFailure = false;
78
79
    /**
80
     * Validator constructor.
81
     *
82
     * @param array $data
83
     * @param array $rules
84
     * @param array $messages
85
     */
86
    public function __construct(array $data, array $rules, array $messages = [])
87
    {
88
        $this->data = new Data($data);
89
        $this->rules = $rules;
90
        $this->messages = $messages;
91
        $instantiator = new Instantiator();
92
        $this->repository = new Repository($instantiator);
93
        $this->normalizer = new ArrayNormalizer(new Parser($this->repository));
94
        $this->errors = new Errors($messages);
95
    }
96
97
    /**
98
     * Extends available rules with new ones.
99
     *
100
     * @param array $rules
101
     *
102
     * @return $this
103
     */
104
    public function extend(array $rules)
105
    {
106
        $this->repository->add($rules);
107
108
        return $this;
109
    }
110
111
    /**
112
     * Returns all available validation rules.
113
     *
114
     * @return array
115
     */
116
    public function getAvailable()
117
    {
118
        return $this->repository->all();
119
    }
120
121
    /**
122
     * Returns data that's being validated.
123
     *
124
     * @return array
125
     */
126
    public function getData()
127
    {
128
        return $this->data->raw();
129
    }
130
131
    /**
132
     * Sets data that need to be validated.
133
     *
134
     * @param array $data
135
     *
136
     * @return $this
137
     */
138
    public function setData(array $data)
139
    {
140
        $this->data = new Data($data);
141
142
        return $this;
143
    }
144
145
    /**
146
     * Returns validation rules.
147
     *
148
     * @return array
149
     */
150
    public function getRules()
151
    {
152
        return $this->rules;
153
    }
154
155
    /**
156
     * Checks proper format of the validation rules and sets them for the validator.
157
     *
158
     * @param array $rules
159
     *
160
     * @return $this
161
     * @throws UnexpectedValueException
162
     */
163
    public function setRules(array $rules)
164
    {
165
        $this->rules = $rules;
166
        $this->normalizedRules = $this->normalizer->normalize($rules);
167
168
        return $this;
169
    }
170
171
    /**
172
     * Returns validation messages.
173
     *
174
     * @return array
175
     */
176
    public function getMessages()
177
    {
178
        return $this->messages;
179
    }
180
181
    /**
182
     * Sets validation messages.
183
     *
184
     * @param array $messages
185
     *
186
     * @return $this
187
     */
188
    public function setMessages(array $messages)
189
    {
190
        $this->messages = $messages;
191
192
        return $this;
193
    }
194
195
    /**
196
     * Validates given data.
197
     *
198
     * @return bool
199
     * @throws UnexpectedValueException
200
     */
201
    public function validate()
202
    {
203
        if (empty($this->normalizedRules)) {
204
            $this->normalizedRules = $this->normalizer->normalize($this->rules);
205
        }
206
207
        foreach ($this->normalizedRules as $attrName => $rules) {
208
            foreach ($rules as $rule) {
209
                $attribute = $this->data->get($attrName);
210
                $rule = is_callable($rule)
211
                    ? new CallableRuleWrapper($rule($attribute->getValue()))
212
                    : $rule;
213
214
                if ($attribute->canSkip($rule)) {
215
                    continue 2;
216
                }
217
218
                if ($attribute->conformsTo($rule)) {
219
                    continue;
220
                }
221
222
                $this->errors->add($attribute, $rule);
223
224
                if ($rule instanceof UntilFirstFailure) {
225
                    continue 2;
226
                }
227
228
                if ($rule instanceof StopsFurtherValidationInterface ||
229
                    $this->shouldStopOnFirstFailure) {
230
                    return false;
231
                }
232
            }
233
        }
234
        
235
        return $this->errors->isEmpty();
236
    }
237
238
    /**
239
     * Checks whether there are validation errors.
240
     *
241
     * @return bool
242
     */
243
    public function hasErrors()
244
    {
245
        return !$this->errors->isEmpty();
246
    }
247
248
    /**
249
     * Returns all validation errors.
250
     *
251
     * @return array
252
     */
253
    public function getErrors()
254
    {
255
        return $this->errors->raw();
256
    }
257
258
    /**
259
     * Returns a plain validation errors array without their attribute names.
260
     *
261
     * @return array
262
     */
263
    public function getErrorsList()
264
    {
265
        return $this->errors->flatten();
266
    }
267
268
    /**
269
     * Determines whether validation should stop on the first failure.
270
     *
271
     * @param bool $stop
272
     *
273
     * @return $this
274
     */
275
    public function shouldStopOnFirstFailure($stop = true)
276
    {
277
        $this->shouldStopOnFirstFailure = $stop;
278
279
        return $this;
280
    }
281
}
282