Completed
Pull Request — master (#56)
by
unknown
12:46
created

Validation::validate()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 12
cts 12
cp 1
rs 8.8657
c 0
b 0
f 0
cc 6
nc 7
nop 3
crap 6
1
<?php
2
3
namespace DavidePastore\Slim\Validation;
4
5
use Psr\Http\Message\ResponseInterface;
6
use Psr\Http\Message\ServerRequestInterface;
7
use Psr\Http\Server\RequestHandlerInterface;
8
use Respect\Validation\Exceptions\NestedValidationException;
9
use Slim\Routing\RouteContext;
10
11
/**
12
 * Validation for Slim.
13
 */
14
class Validation
15
{
16
    /**
17
     * Validators.
18
     *
19
     * @var array
20
     */
21
    protected $validators = [];
22
23
    /**
24
     * Options.
25
     *
26
     * @var array
27
     */
28
    protected $options = [
29
        'useTemplate' => false,
30
    ];
31
32
    /**
33
     * The translator to use fro the exception message.
34
     *
35
     * @var callable
36
     */
37
    protected $translator = null;
38
39
    /**
40
     * Errors from the validation.
41
     *
42
     * @var array
43
     */
44
    protected $errors = [];
45
46
    /**
47
     * The 'errors' attribute name.
48
     *
49
     * @var string
50
     */
51
    protected $errors_name = 'errors';
52
53
    /**
54
     * The 'has_error' attribute name.
55
     *
56
     * @var string
57
     */
58
    protected $has_errors_name = 'has_errors';
59
60
    /**
61
     * The 'validators' attribute name.
62
     *
63
     * @var string
64
     */
65
    protected $validators_name = 'validators';
66
67
    /**
68
     * The 'translator' attribute name.
69
     *
70
     * @var string
71
     */
72
    protected $translator_name = 'translator';
73
74
    /**
75
     * Create new Validator service provider.
76 25
     *
77
     * @param null|array|ArrayAccess $validators
78
     * @param null|callable          $translator
79 25
     * @param []|array               $options
0 ignored issues
show
Documentation introduced by
The doc-type []|array could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
80 24
     */
81 25
    public function __construct($validators = null, $translator = null, $options = [])
82 1
    {
83 1
        // Set the validators
84 25
        if (is_array($validators) || $validators instanceof \ArrayAccess) {
85 25
            $this->validators = $validators;
86 25
        } elseif (is_null($validators)) {
87
            $this->validators = [];
88
        }
89
        $this->translator = $translator;
90
        $this->options = array_merge($this->options, $options);
91
    }
92
93
    /**
94
     * Validation middleware invokable class.
95
     *
96
     * @param \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
97 25
     * @param \Psr\Http\Message\ResponseInterface      $response PSR7 response
0 ignored issues
show
Bug introduced by
There is no parameter named $response. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
98
     * @param callable                                 $next     Next middleware
0 ignored issues
show
Bug introduced by
There is no parameter named $next. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
99 25
     *
100 25
     * @return \Psr\Http\Message\ResponseInterface
101 25
     */
102 25
    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
103
    {
104 25
        $this->errors = [];
105 25
        $params = $request->getParsedBody();
106 25
107 25
        $routeContext = RouteContext::fromRequest($request);
108
        $route = $routeContext->getRoute();
109 25
        $arguments = $route->getArguments();
110
111
        $params = array_merge((array) $arguments, (array)$params);
112
113
        $this->validate($params, $this->validators);
114
115
        $request = $request->withAttribute($this->errors_name, $this->getErrors());
116
        $request = $request->withAttribute($this->has_errors_name, $this->hasErrors());
117
        $request = $request->withAttribute($this->validators_name, $this->getValidators());
118
        $request = $request->withAttribute($this->translator_name, $this->getTranslator());
119
120 25
        return $handler->handle($request);
121
    }
122
123 25
    /**
124 24
     * Validate the parameters by the given params, validators and actual keys.
125 24
     * This method populates the $errors attribute.
126 24
     *
127 9
     * @param array $params     The array of parameters.
128 9
     * @param array $validators The array of validators.
129
     * @param array $actualKeys An array that will save all the keys of the tree to retrieve the correct value.
130 24
     */
131 24
    private function validate($params = [], $validators = [], $actualKeys = [])
132 14
    {
133 2
        //Validate every parameters in the validators array
134 2
        foreach ($validators as $key => $validator) {
135 14
            $actualKeys[] = $key;
136
            $param = $this->getNestedParam($params, $actualKeys);
137
            if (is_array($validator)) {
138
                $this->validate($params, $validator, $actualKeys);
139
            } else {
140 24
                try {
141 25
                    $validator->assert($param);
142 25
                } catch (NestedValidationException $exception) {
143
                    if ($this->translator) {
144
                        $exception->setParam('translator', $this->translator);
0 ignored issues
show
Bug introduced by
The method setParam() does not seem to exist on object<Respect\Validatio...tedValidationException>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
145
                    }
146
                    if ($this->options['useTemplate']) {
147
                        $this->errors[implode('.', $actualKeys)] = [$exception->getMainMessage()];
0 ignored issues
show
Bug introduced by
The method getMainMessage() does not seem to exist on object<Respect\Validatio...tedValidationException>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
148
                    } else {
149
                        $this->errors[implode('.', $actualKeys)] = $exception->getMessages();
150
                    }
151
                }
152 24
            }
153
154 24
            //Remove the key added in this foreach
155 22
            array_pop($actualKeys);
156
        }
157 24
    }
158 24
159 22
    /**
160 22
     * Get the nested parameter value.
161
     *
162 22
     * @param array $params An array that represents the values of the parameters.
163 14
     * @param array $keys   An array that represents the tree of keys to use.
164 3
     *
165
     * @return mixed The nested parameter value by the given params and tree of keys.
166
     */
167
    private function getNestedParam($params = [], $keys = [])
168
    {
169
        if (empty($keys)) {
170
            return $params;
171
        } else {
172
            $firstKey = array_shift($keys);
173
            if ($this->isArrayLike($params) && array_key_exists($firstKey, $params)) {
174
                $params = (array) $params;
175
                $paramValue = $params[$firstKey];
176 24
177
                return $this->getNestedParam($paramValue, $keys);
178 24
            } else {
179
                return;
180
            }
181
        }
182
    }
183
184
    /**
185
     * Check if the given $params is an array like variable.
186 25
     *
187
     * @param array $params The variable to check.
188 25
     *
189
     * @return boolean Returns true if the given $params parameter is array like.
190
     */
191
    private function isArrayLike($params)
192
    {
193
        return is_array($params) || $params instanceof \SimpleXMLElement;
194
    }
195
196 25
    /**
197
     * Check if there are any errors.
198 25
     *
199
     * @return bool
200
     */
201
    public function hasErrors()
202
    {
203
        return !empty($this->errors);
204
    }
205
206 25
    /**
207
     * Get errors.
208 25
     *
209
     * @return array The errors array.
210
     */
211
    public function getErrors()
212
    {
213
        return $this->errors;
214
    }
215
216 1
    /**
217
     * Get validators.
218 1
     *
219 1
     * @return array The validators array.
220
     */
221
    public function getValidators()
222
    {
223
        return $this->validators;
224
    }
225
226 25
    /**
227
     * Set validators.
228 25
     *
229
     * @param array $validators The validators array.
230
     */
231
    public function setValidators($validators)
232
    {
233
        $this->validators = $validators;
234
    }
235
236 1
    /**
237
     * Get translator.
238 1
     *
239 1
     * @return callable The translator.
240
     */
241
    public function getTranslator()
242
    {
243
        return $this->translator;
244
    }
245
246
    /**
247
     * Set translator.
248
     *
249
     * @param callable $translator The translator.
250
     */
251
    public function setTranslator($translator)
252
    {
253
        $this->translator = $translator;
254
    }
255
}
256