Issues (125)

RequestQueryParameterResolver.php (1 issue)

Severity
1
<?php
2
3
/**
4
 * It's free open-source software released under the MIT License.
5
 *
6
 * @author Anatoly Nekhay <[email protected]>
7
 * @copyright Copyright (c) 2018, Anatoly Nekhay
8
 * @license https://github.com/sunrise-php/http-router/blob/master/LICENSE
9
 * @link https://github.com/sunrise-php/http-router
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sunrise\Http\Router\ParameterResolver;
15
16
use Generator;
17
use InvalidArgumentException;
18
use Psr\Http\Message\ServerRequestInterface;
19
use ReflectionAttribute;
20
use ReflectionNamedType;
21
use ReflectionParameter;
22
use Sunrise\Http\Router\Annotation\RequestQuery;
23
use Sunrise\Http\Router\Exception\HttpException;
24
use Sunrise\Http\Router\Exception\HttpExceptionFactory;
25
use Sunrise\Http\Router\ParameterResolverChain;
26
use Sunrise\Http\Router\ParameterResolverInterface;
27
use Sunrise\Http\Router\Validation\ConstraintViolation\HydratorConstraintViolationAdapter;
28
use Sunrise\Http\Router\Validation\ConstraintViolation\ValidatorConstraintViolationAdapter;
29
use Sunrise\Hydrator\Exception\InvalidDataException;
30
use Sunrise\Hydrator\Exception\InvalidObjectException;
31
use Sunrise\Hydrator\HydratorInterface;
32
use Symfony\Component\Validator\Validator\ValidatorInterface;
33
34
use function array_map;
35
use function sprintf;
36
37
/**
38
 * @since 3.0.0
39
 */
40
final class RequestQueryParameterResolver implements ParameterResolverInterface
41
{
42 16
    public function __construct(
43
        private readonly HydratorInterface $hydrator,
44
        private readonly ?ValidatorInterface $validator = null,
45
        private readonly ?int $defaultErrorStatusCode = null,
46
        private readonly ?string $defaultErrorMessage = null,
47
        /** @var array<string, mixed> */
48
        private readonly array $hydratorContext = [],
49
        private readonly bool $defaultValidationEnabled = true,
50
    ) {
51 16
    }
52
53
    /**
54
     * @inheritDoc
55
     *
56
     * @throws HttpException
57
     * @throws InvalidArgumentException
58
     * @throws InvalidObjectException
59
     */
60 15
    public function resolveParameter(ReflectionParameter $parameter, mixed $context): Generator
61
    {
62 15
        if (! $context instanceof ServerRequestInterface) {
63 1
            return;
64
        }
65
66
        /** @var list<ReflectionAttribute<RequestQuery>> $annotations */
67 14
        $annotations = $parameter->getAttributes(RequestQuery::class);
68 14
        if ($annotations === []) {
0 ignored issues
show
The condition $annotations === array() is always false.
Loading history...
69 1
            return;
70
        }
71
72 13
        $type = $parameter->getType();
73 13
        if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) {
74 2
            throw new InvalidArgumentException(sprintf(
75 2
                'To use the #[RequestQuery] annotation, the parameter "%s" must be typed with an object.',
76 2
                ParameterResolverChain::stringifyParameter($parameter),
77 2
            ));
78
        }
79
80
        /** @var class-string $className */
81 11
        $className = $type->getName();
82 11
        $processParams = $annotations[0]->newInstance();
83 11
        $errorStatusCode = $processParams->errorStatusCode ?? $this->defaultErrorStatusCode;
84 11
        $errorMessage = $processParams->errorMessage ?? $this->defaultErrorMessage;
85 11
        $hydratorContext = $processParams->hydratorContext + $this->hydratorContext;
86 11
        $validationEnabled = $processParams->validationEnabled ?? $this->defaultValidationEnabled;
87
88
        try {
89 11
            $argument = $this->hydrator->hydrate($className, $context->getQueryParams(), context: $hydratorContext);
90 5
        } catch (InvalidDataException $e) {
91 5
            throw HttpExceptionFactory::invalidQuery($errorMessage, $errorStatusCode, previous: $e)
92 5
                ->addConstraintViolation(...array_map(
93 5
                    HydratorConstraintViolationAdapter::create(...),
94 5
                    $e->getExceptions(),
95 5
                ));
96
        }
97
98 6
        if ($this->validator !== null && $validationEnabled) {
99 2
            $violations = $this->validator->validate($argument);
100 2
            if ($violations->count() > 0) {
101 1
                throw HttpExceptionFactory::invalidQuery($errorMessage, $errorStatusCode)
102 1
                    ->addConstraintViolation(...array_map(
103 1
                        ValidatorConstraintViolationAdapter::create(...),
104 1
                        [...$violations],
105 1
                    ));
106
            }
107
        }
108
109 5
        yield $argument;
110
    }
111
112 1
    public function getWeight(): int
113
    {
114 1
        return 0;
115
    }
116
}
117