RequestCookieParameterResolver::getWeight()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
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 Psr\Http\Message\ServerRequestInterface;
18
use ReflectionAttribute;
19
use ReflectionParameter;
20
use Sunrise\Http\Router\Annotation\RequestCookie;
21
use Sunrise\Http\Router\Dictionary\PlaceholderCode;
22
use Sunrise\Http\Router\Exception\HttpException;
23
use Sunrise\Http\Router\Exception\HttpExceptionFactory;
24
use Sunrise\Http\Router\ParameterResolverInterface;
25
use Sunrise\Http\Router\ServerRequest;
26
use Sunrise\Http\Router\Validation\Constraint\ArgumentConstraint;
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\Exception\InvalidValueException;
32
use Sunrise\Hydrator\HydratorInterface;
33
use Sunrise\Hydrator\Type;
34
use Symfony\Component\Validator\Validator\ValidatorInterface;
35
36
use function array_map;
37
38
/**
39
 * @since 3.0.0
40
 */
41
final class RequestCookieParameterResolver implements ParameterResolverInterface
42
{
43 17
    public function __construct(
44
        private readonly HydratorInterface $hydrator,
45
        private readonly ?ValidatorInterface $validator = null,
46
        private readonly ?int $defaultErrorStatusCode = null,
47
        private readonly ?string $defaultErrorMessage = null,
48
        /** @var array<string, mixed> */
49
        private readonly array $hydratorContext = [],
50
        private readonly bool $defaultValidationEnabled = true,
51
    ) {
52 17
    }
53
54
    /**
55
     * @inheritDoc
56
     *
57
     * @throws HttpException
58
     * @throws InvalidObjectException
59
     */
60 16
    public function resolveParameter(ReflectionParameter $parameter, mixed $context): Generator
61
    {
62 16
        if (! $context instanceof ServerRequestInterface) {
63 1
            return;
64
        }
65
66
        /** @var list<ReflectionAttribute<RequestCookie>> $annotations */
67 15
        $annotations = $parameter->getAttributes(RequestCookie::class);
68 15
        if ($annotations === []) {
0 ignored issues
show
introduced by
The condition $annotations === array() is always false.
Loading history...
69 1
            return;
70
        }
71
72 14
        $request = ServerRequest::create($context);
73 14
        $requestCookieParams = $request->getCookieParams();
74 14
        $processParams = $annotations[0]->newInstance();
75 14
        $cookieName = $processParams->name;
76 14
        $errorStatusCode = $processParams->errorStatusCode ?? $this->defaultErrorStatusCode;
77 14
        $errorMessage = $processParams->errorMessage ?? $this->defaultErrorMessage;
78 14
        $hydratorContext = $processParams->hydratorContext + $this->hydratorContext;
79 14
        $validationEnabled = $processParams->validationEnabled ?? $this->defaultValidationEnabled;
80
81 14
        if (!isset($requestCookieParams[$cookieName])) {
82 2
            if ($parameter->isDefaultValueAvailable()) {
83 1
                return yield $parameter->getDefaultValue();
84
            }
85
86 1
            throw HttpExceptionFactory::missingCookie($errorMessage, $errorStatusCode)
87 1
                ->addMessagePlaceholder(PlaceholderCode::COOKIE_NAME, $cookieName);
88
        }
89
90
        try {
91 12
            $argument = $this->hydrator->castValue(
92 12
                $requestCookieParams[$cookieName],
93 12
                Type::fromParameter($parameter),
94 12
                path: [$cookieName],
95 12
                context: $hydratorContext,
96 12
            );
97 6
        } catch (InvalidValueException $e) {
98 5
            throw HttpExceptionFactory::invalidCookie($errorMessage, $errorStatusCode, previous: $e)
99 5
                ->addMessagePlaceholder(PlaceholderCode::COOKIE_NAME, $cookieName)
100 5
                ->addConstraintViolation(new HydratorConstraintViolationAdapter($e));
101 1
        } catch (InvalidDataException $e) {
102 1
            throw HttpExceptionFactory::invalidCookie($errorMessage, $errorStatusCode, previous: $e)
103 1
                ->addMessagePlaceholder(PlaceholderCode::COOKIE_NAME, $cookieName)
104 1
                ->addConstraintViolation(...array_map(
105 1
                    HydratorConstraintViolationAdapter::create(...),
106 1
                    $e->getExceptions(),
107 1
                ));
108
        }
109
110 6
        if ($this->validator !== null && $validationEnabled) {
111 2
            $violations = $this->validator
112 2
                ->startContext()
113 2
                ->atPath($cookieName)
114 2
                ->validate($argument, new ArgumentConstraint($parameter))
115 2
                ->getViolations();
116
117 2
            if ($violations->count() > 0) {
118 1
                throw HttpExceptionFactory::invalidCookie($errorMessage, $errorStatusCode)
119 1
                    ->addMessagePlaceholder(PlaceholderCode::COOKIE_NAME, $cookieName)
120 1
                    ->addConstraintViolation(...array_map(
121 1
                        ValidatorConstraintViolationAdapter::create(...),
122 1
                        [...$violations],
123 1
                    ));
124
            }
125
        }
126
127 5
        yield $argument;
128
    }
129
130 1
    public function getWeight(): int
131
    {
132 1
        return 0;
133
    }
134
}
135