resolveParameter()   B
last analyzed

Complexity

Conditions 10
Paths 9

Size

Total Lines 77
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 59
CRAP Score 10

Importance

Changes 0
Metric Value
cc 10
eloc 54
c 0
b 0
f 0
nc 9
nop 2
dl 0
loc 77
ccs 59
cts 59
cp 1
crap 10
rs 7.1369

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 ReflectionParameter;
21
use Sunrise\Http\Router\Annotation\RequestVariable;
22
use Sunrise\Http\Router\Dictionary\PlaceholderCode;
23
use Sunrise\Http\Router\Exception\HttpException;
24
use Sunrise\Http\Router\Exception\HttpExceptionFactory;
25
use Sunrise\Http\Router\Helper\RouteSimplifier;
26
use Sunrise\Http\Router\ParameterResolverChain;
27
use Sunrise\Http\Router\ParameterResolverInterface;
28
use Sunrise\Http\Router\ServerRequest;
29
use Sunrise\Http\Router\Validation\Constraint\ArgumentConstraint;
30
use Sunrise\Http\Router\Validation\ConstraintViolation\HydratorConstraintViolationAdapter;
31
use Sunrise\Http\Router\Validation\ConstraintViolation\ValidatorConstraintViolationAdapter;
32
use Sunrise\Hydrator\Exception\InvalidDataException;
33
use Sunrise\Hydrator\Exception\InvalidObjectException;
34
use Sunrise\Hydrator\Exception\InvalidValueException;
35
use Sunrise\Hydrator\HydratorInterface;
36
use Sunrise\Hydrator\Type;
37
use Symfony\Component\Validator\Validator\ValidatorInterface;
38
39
use function array_map;
40
use function sprintf;
41
42
/**
43
 * @since 3.0.0
44
 */
45
final class RequestVariableParameterResolver implements ParameterResolverInterface
46
{
47 17
    public function __construct(
48
        private readonly HydratorInterface $hydrator,
49
        private readonly ?ValidatorInterface $validator = null,
50
        private readonly ?int $defaultErrorStatusCode = null,
51
        private readonly ?string $defaultErrorMessage = null,
52
        /** @var array<string, mixed> */
53
        private readonly array $hydratorContext = [],
54
        private readonly bool $defaultValidationEnabled = true,
55
    ) {
56 17
    }
57
58
    /**
59
     * @inheritDoc
60
     *
61
     * @throws HttpException
62
     * @throws InvalidArgumentException
63
     * @throws InvalidObjectException
64
     */
65 16
    public function resolveParameter(ReflectionParameter $parameter, mixed $context): Generator
66
    {
67 16
        if (! $context instanceof ServerRequestInterface) {
68 1
            return;
69
        }
70
71
        /** @var list<ReflectionAttribute<RequestVariable>> $annotations */
72 15
        $annotations = $parameter->getAttributes(RequestVariable::class);
73 15
        if ($annotations === []) {
0 ignored issues
show
introduced by
The condition $annotations === array() is always false.
Loading history...
74 1
            return;
75
        }
76
77 14
        $route = ServerRequest::create($context)->getRoute();
78 14
        $processParams = $annotations[0]->newInstance();
79 14
        $variableName = $processParams->name ?? $parameter->name;
80 14
        $errorStatusCode = $processParams->errorStatusCode ?? $this->defaultErrorStatusCode;
81 14
        $errorMessage = $processParams->errorMessage ?? $this->defaultErrorMessage;
82 14
        $hydratorContext = $processParams->hydratorContext + $this->hydratorContext;
83 14
        $validationEnabled = $processParams->validationEnabled ?? $this->defaultValidationEnabled;
84
85 14
        if (!$route->hasAttribute($variableName)) {
86 2
            if ($parameter->isDefaultValueAvailable()) {
87 1
                return yield $parameter->getDefaultValue();
88
            }
89
90 1
            throw new InvalidArgumentException(sprintf(
91 1
                'The parameter "%s" expects a value of the variable {%s} from the route "%s", ' .
92 1
                'which is not present in the request, likely because the variable is optional. ' .
93 1
                'To resolve this issue, assign the default value to the parameter.',
94 1
                ParameterResolverChain::stringifyParameter($parameter),
95 1
                $variableName,
96 1
                $route->getName(),
97 1
            ));
98
        }
99
100
        try {
101 12
            $argument = $this->hydrator->castValue(
102 12
                $route->getAttribute($variableName),
103 12
                Type::fromParameter($parameter),
104 12
                path: [$variableName],
105 12
                context: $hydratorContext,
106 12
            );
107 6
        } catch (InvalidValueException $e) {
108 5
            throw HttpExceptionFactory::invalidVariable($errorMessage, $errorStatusCode, previous: $e)
109 5
                ->addMessagePlaceholder(PlaceholderCode::VARIABLE_NAME, $variableName)
110 5
                ->addMessagePlaceholder(PlaceholderCode::ROUTE_URI, RouteSimplifier::simplifyRoute($route->getPath()))
111 5
                ->addConstraintViolation(new HydratorConstraintViolationAdapter($e));
112 1
        } catch (InvalidDataException $e) {
113 1
            throw HttpExceptionFactory::invalidVariable($errorMessage, $errorStatusCode, previous: $e)
114 1
                ->addMessagePlaceholder(PlaceholderCode::VARIABLE_NAME, $variableName)
115 1
                ->addMessagePlaceholder(PlaceholderCode::ROUTE_URI, RouteSimplifier::simplifyRoute($route->getPath()))
116 1
                ->addConstraintViolation(...array_map(
117 1
                    HydratorConstraintViolationAdapter::create(...),
118 1
                    $e->getExceptions(),
119 1
                ));
120
        }
121
122 6
        if ($this->validator !== null && $validationEnabled) {
123 2
            $violations = $this->validator
124 2
                ->startContext()
125 2
                ->atPath($variableName)
126 2
                ->validate($argument, new ArgumentConstraint($parameter))
127 2
                ->getViolations();
128
129 2
            if ($violations->count() > 0) {
130 1
                throw HttpExceptionFactory::invalidVariable($errorMessage, $errorStatusCode)
131 1
                    ->addMessagePlaceholder(PlaceholderCode::VARIABLE_NAME, $variableName)
132 1
                    // phpcs:ignore Generic.Files.LineLength.TooLong
133 1
                    ->addMessagePlaceholder(PlaceholderCode::ROUTE_URI, RouteSimplifier::simplifyRoute($route->getPath()))
134 1
                    ->addConstraintViolation(...array_map(
135 1
                        ValidatorConstraintViolationAdapter::create(...),
136 1
                        [...$violations],
137 1
                    ));
138
            }
139
        }
140
141 5
        yield $argument;
142
    }
143
144 1
    public function getWeight(): int
145
    {
146 1
        return 0;
147
    }
148
}
149