Completed
Push — master ( 0a3bde...b47c78 )
by Alexis
01:19
created

Validator   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 311
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 41
lcom 1
cbo 3
dl 0
loc 311
rs 8.2769
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A isValid() 0 4 1
D validate() 0 59 16
A addError() 0 6 1
A addErrors() 0 8 2
A getData() 0 4 1
A getErrors() 0 4 1
A getFirstError() 0 10 2
A getParamErrors() 0 4 2
A getParamRuleError() 0 4 2
B getRequestParam() 0 16 6
A getValue() 0 4 2
A setData() 0 6 1
A setErrors() 0 5 1
A setParamErrors() 0 6 1
A setValues() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like Validator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Validator, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Awurth\SlimValidation;
4
5
use InvalidArgumentException;
6
use Psr\Http\Message\ServerRequestInterface as Request;
7
use ReflectionClass;
8
use Respect\Validation\Exceptions\NestedValidationException;
9
use Respect\Validation\Validator as V;
10
11
/**
12
 * Validator.
13
 *
14
 * @author Alexis Wurth <[email protected]>
15
 */
16
class Validator
17
{
18
    /**
19
     * The validated data.
20
     *
21
     * @var array
22
     */
23
    protected $data;
24
25
    /**
26
     * The default error messages for the given rules.
27
     *
28
     * @var array
29
     */
30
    protected $defaultMessages;
31
32
    /**
33
     * The list of validation errors.
34
     *
35
     * @var array
36
     */
37
    protected $errors;
38
39
    /**
40
     * Tells if errors should be stored in an associative array
41
     * where the key is the name of the validation rule.
42
     *
43
     * @var bool
44
     */
45
    protected $storeErrorsWithRules;
46
47
    /**
48
     * Constructor.
49
     *
50
     * @param bool $storeErrorsWithRules
51
     * @param array $defaultMessages
52
     */
53
    public function __construct($storeErrorsWithRules = true, array $defaultMessages = [])
54
    {
55
        $this->storeErrorsWithRules = $storeErrorsWithRules;
56
        $this->defaultMessages = $defaultMessages;
57
    }
58
59
    /**
60
     * Tells if there is no error.
61
     *
62
     * @return bool
63
     */
64
    public function isValid()
65
    {
66
        return empty($this->errors);
67
    }
68
69
    /**
70
     * Validates request parameters with the given rules.
71
     *
72
     * @param Request $request
73
     * @param array $rules
74
     * @param array $messages
75
     *
76
     * @return $this
77
     */
78
    public function validate(Request $request, array $rules, array $messages = [])
79
    {
80
        foreach ($rules as $param => $options) {
81
            $value = $this->getRequestParam($request, $param);
82
            $this->data[$param] = $value;
83
            $isRule = $options instanceof V;
84
85
            try {
86
                if ($isRule) {
87
                    $options->assert($value);
88
                } else {
89
                    if (!isset($options['rules']) || !($options['rules'] instanceof V)) {
90
                        throw new InvalidArgumentException('Validation rules are missing');
91
                    }
92
93
                    $options['rules']->assert($value);
94
                }
95
            } catch (NestedValidationException $e) {
96
                $paramRules = $isRule ? $options->getRules() : $options['rules']->getRules();
97
98
                // Get the names of all rules used for this param
99
                $rulesNames = [];
100
                foreach ($paramRules as $rule) {
101
                    $rulesNames[] = lcfirst((new ReflectionClass($rule))->getShortName());
102
                }
103
104
                // If the 'message' key exists, set it as only message for this param
105
                if (!$isRule && isset($options['message']) && is_string($options['message'])) {
106
                    $this->errors[$param] = [$options['message']];
107
                    return $this;
108
                } else { // If the 'messages' key exists, override global messages
109
                    $params = [
110
                        $e->findMessages($rulesNames)
111
                    ];
112
113
                    // If default messages are defined
114
                    if (!empty($this->defaultMessages)) {
115
                        $params[] = $e->findMessages($this->defaultMessages);
116
                    }
117
118
                    // If global messages are defined
119
                    if (!empty($messages)) {
120
                        $params[] = $e->findMessages($messages);
121
                    }
122
123
                    // If individual messages are defined
124
                    if (!$isRule && isset($options['messages'])) {
125
                        $params[] = $e->findMessages($options['messages']);
126
                    }
127
128
                    $errors = array_filter(call_user_func_array('array_merge', $params));
129
130
                    $this->errors[$param] = $this->storeErrorsWithRules ? $errors : array_values($errors);
131
                }
132
            }
133
        }
134
135
        return $this;
136
    }
137
138
    /**
139
     * Adds an error for a parameter.
140
     *
141
     * @param string $param
142
     * @param string $message
143
     *
144
     * @return $this
145
     */
146
    public function addError($param, $message)
147
    {
148
        $this->errors[$param][] = $message;
149
150
        return $this;
151
    }
152
153
    /**
154
     * Adds errors for a parameter.
155
     *
156
     * @param string $param
157
     * @param string[] $messages
158
     *
159
     * @return $this
160
     */
161
    public function addErrors($param, array $messages)
162
    {
163
        foreach ($messages as $message) {
164
            $this->errors[$param][] = $message;
165
        }
166
167
        return $this;
168
    }
169
170
    /**
171
     * Gets the validated data.
172
     *
173
     * @return array
174
     */
175
    public function getData()
176
    {
177
        return $this->data;
178
    }
179
180
    /**
181
     * Gets all errors.
182
     *
183
     * @return array
184
     */
185
    public function getErrors()
186
    {
187
        return $this->errors;
188
    }
189
190
    /**
191
     * Gets the first error of a parameter.
192
     *
193
     * @param string $param
194
     *
195
     * @return string
196
     */
197
    public function getFirstError($param)
198
    {
199
        if (isset($this->errors[$param])) {
200
            $first = array_slice($this->errors[$param], 0, 1);
201
202
            return array_shift($first);
203
        }
204
205
        return '';
206
    }
207
208
    /**
209
     * Gets errors of a parameter.
210
     *
211
     * @param string $param
212
     *
213
     * @return string[]
214
     */
215
    public function getParamErrors($param)
216
    {
217
        return isset($this->errors[$param]) ? $this->errors[$param] : [];
218
    }
219
220
    /**
221
     * Gets the error of a validation rule for a parameter.
222
     *
223
     * @param string $param
224
     * @param string $rule
225
     *
226
     * @return string
227
     */
228
    public function getParamRuleError($param, $rule)
229
    {
230
        return isset($this->errors[$param][$rule]) ? $this->errors[$param][$rule] : '';
231
    }
232
233
    /**
234
     * Fetch request parameter value from body or query string (in that order).
235
     *
236
     * @param  Request $request
237
     * @param  string  $key The parameter key.
238
     * @param  string  $default The default value.
239
     *
240
     * @return mixed The parameter value.
241
     */
242
    public function getRequestParam(Request $request, $key, $default = null)
243
    {
244
        $postParams = $request->getParsedBody();
245
        $getParams = $request->getQueryParams();
246
247
        $result = $default;
248
        if (is_array($postParams) && isset($postParams[$key])) {
249
            $result = $postParams[$key];
250
        } elseif (is_object($postParams) && property_exists($postParams, $key)) {
251
            $result = $postParams->$key;
252
        } elseif (isset($getParams[$key])) {
253
            $result = $getParams[$key];
254
        }
255
256
        return $result;
257
    }
258
259
    /**
260
     * Gets the value of a parameter in validated data.
261
     *
262
     * @param string $param
263
     *
264
     * @return string
265
     */
266
    public function getValue($param)
267
    {
268
        return isset($this->data[$param]) ? $this->data[$param] : '';
269
    }
270
271
    /**
272
     * Sets the validator data.
273
     *
274
     * @param array $data
275
     *
276
     * @return $this
277
     */
278
    public function setData(array $data)
279
    {
280
        $this->data = $data;
281
282
        return $this;
283
    }
284
285
    /**
286
     * Sets all errors.
287
     *
288
     * @param array $errors
289
     *
290
     * @return $this
291
     */
292
    public function setErrors(array $errors)
293
    {
294
        $this->errors = $errors;
295
        return $this;
296
    }
297
298
    /**
299
     * Sets the errors of a parameter.
300
     *
301
     * @param string $param
302
     * @param string[] $errors
303
     *
304
     * @return $this
305
     */
306
    public function setParamErrors($param, array $errors)
307
    {
308
        $this->errors[$param] = $errors;
309
310
        return $this;
311
    }
312
313
    /**
314
     * Sets the value of parameters.
315
     *
316
     * @param array $data
317
     *
318
     * @return $this
319
     */
320
    public function setValues(array $data)
321
    {
322
        $this->data = array_merge($this->data, $data);
323
324
        return $this;
325
    }
326
}
327