RequestParameterValidator   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 78
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 39
c 1
b 0
f 0
dl 0
loc 78
rs 10
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A validateQueryParameter() 0 34 5
A validate() 0 24 3
A getValidateQueryParametersFromRequest() 0 4 1
A __construct() 0 3 1
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
/**
28
 * Validates the query parameters of the request with the schema from the OpenAPI document.
29
 *
30
 * @experimental
31
 *
32
 * @author Niels Nijens <[email protected]>
33
 */
34
final class RequestParameterValidator implements ValidatorInterface
35
{
36
    /**
37
     * @var Validator
38
     */
39
    private $jsonValidator;
40
41
    public function __construct(Validator $jsonValidator)
42
    {
43
        $this->jsonValidator = $jsonValidator;
44
    }
45
46
    public function validate(Request $request): ?RequestProblemExceptionInterface
47
    {
48
        $validateQueryParameters = $this->getValidateQueryParametersFromRequest($request);
49
50
        $violations = [];
51
        foreach ($validateQueryParameters as $parameterName => $parameter) {
52
            $violations = array_merge(
53
                $violations,
54
                $this->validateQueryParameter($request, $parameterName, json_decode($parameter))
55
            );
56
        }
57
58
        if (count($violations) > 0) {
59
            $exception = new InvalidRequestParameterProblemException(
60
                ProblemException::DEFAULT_TYPE_URI,
61
                'The request contains errors.',
62
                Response::HTTP_BAD_REQUEST,
63
                'Validation of query parameters failed.'
64
            );
65
66
            return $exception->withViolations($violations);
67
        }
68
69
        return null;
70
    }
71
72
    private function getValidateQueryParametersFromRequest(Request $request): array
73
    {
74
        return $request->attributes
75
            ->get(RouteContext::REQUEST_ATTRIBUTE)[RouteContext::REQUEST_VALIDATE_QUERY_PARAMETERS] ?? [];
76
    }
77
78
    private function validateQueryParameter(Request $request, string $parameterName, stdClass $parameter): array
79
    {
80
        $violations = [];
81
        if ($request->query->has($parameterName) === false && $parameter->required ?? false) {
82
            $violations[] = new Violation(
83
                'required_query_parameter',
84
                sprintf('Query parameter %s is required.', $parameterName),
85
                $parameterName
86
            );
87
88
            return $violations;
89
        }
90
91
        if ($request->query->has($parameterName) === false) {
92
            return $violations;
93
        }
94
95
        $parameterValue = $request->query->get($parameterName);
96
97
        $this->jsonValidator->validate($parameterValue, $parameter->schema, Constraint::CHECK_MODE_COERCE_TYPES);
98
        if ($this->jsonValidator->isValid()) {
99
            return $violations;
100
        }
101
102
        $validationErrors = $this->jsonValidator->getErrors();
103
        $this->jsonValidator->reset();
104
105
        return array_map(
106
            function (array $validationError) use ($parameterName): Violation {
107
                $validationError['property'] = $parameterName;
108
109
                return Violation::fromArray($validationError);
110
            },
111
            $validationErrors
112
        );
113
    }
114
}
115