Passed
Pull Request — main (#71)
by Niels
02:26
created

validateQueryParameter()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 20
c 1
b 0
f 0
nc 4
nop 3
dl 0
loc 34
rs 9.2888
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the OpenapiBundle package.
7
 *
8
 * (c) Niels Nijens <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Nijens\OpenapiBundle\Validation\RequestValidator;
15
16
use JsonSchema\Constraints\Constraint;
17
use JsonSchema\Validator;
18
use Nijens\OpenapiBundle\ExceptionHandling\Exception\InvalidRequestParameterProblemException;
19
use Nijens\OpenapiBundle\ExceptionHandling\Exception\ProblemException;
20
use Nijens\OpenapiBundle\ExceptionHandling\Exception\RequestProblemExceptionInterface;
21
use Nijens\OpenapiBundle\ExceptionHandling\Exception\Violation;
22
use Nijens\OpenapiBundle\Routing\RouteContext;
23
use stdClass;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Response;
26
27
final class RequestParameterValidator implements ValidatorInterface
28
{
29
    /**
30
     * @var Validator
31
     */
32
    private $jsonValidator;
33
34
    public function __construct(Validator $jsonValidator)
35
    {
36
        $this->jsonValidator = $jsonValidator;
37
    }
38
39
    public function validate(Request $request): ?RequestProblemExceptionInterface
40
    {
41
        $validateQueryParameters = $this->getValidateQueryParametersFromRequest($request);
42
43
        $violations = [];
44
        foreach ($validateQueryParameters as $parameterName => $parameter) {
45
            $violations = array_merge(
46
                $violations,
47
                $this->validateQueryParameter($request, $parameterName, json_decode($parameter))
48
            );
49
        }
50
51
        if (count($violations) > 0) {
52
            $exception = new InvalidRequestParameterProblemException(
53
                ProblemException::DEFAULT_TYPE_URI,
54
                'The request contains errors.',
55
                Response::HTTP_BAD_REQUEST,
56
                'Validation of query parameters failed.'
57
            );
58
59
            return $exception->withViolations($violations);
60
        }
61
62
        return null;
63
    }
64
65
    private function getValidateQueryParametersFromRequest(Request $request): array
66
    {
67
        return $request->attributes
68
            ->get(RouteContext::REQUEST_ATTRIBUTE)[RouteContext::REQUEST_VALIDATE_QUERY_PARAMETERS] ?? [];
69
    }
70
71
    private function validateQueryParameter(Request $request, string $parameterName, stdClass $parameter): array
72
    {
73
        $violations = [];
74
        if ($request->query->has($parameterName) === false && $parameter->required ?? false) {
75
            $violations[] = new Violation(
76
                'required_query_parameter',
77
                sprintf('Query parameter %s is required.', $parameterName),
78
                $parameterName
79
            );
80
81
            return $violations;
82
        }
83
84
        if ($request->query->has($parameterName) === false) {
85
            return $violations;
86
        }
87
88
        $parameterValue = $request->query->get($parameterName);
89
90
        $this->jsonValidator->validate($parameterValue, $parameter->schema, Constraint::CHECK_MODE_COERCE_TYPES);
91
        if ($this->jsonValidator->isValid()) {
92
            return $violations;
93
        }
94
95
        $validationErrors = $this->jsonValidator->getErrors();
96
        $this->jsonValidator->reset();
97
98
        return array_map(
99
            function (array $validationError) use ($parameterName): Violation {
100
                $validationError['property'] = $parameterName;
101
102
                return Violation::fromArray($validationError);
103
            },
104
            $validationErrors
105
        );
106
    }
107
}
108