ParameterResolverChain::sortResolvers()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 6
ccs 5
cts 5
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;
15
16
use Generator;
17
use InvalidArgumentException;
18
use LogicException;
19
use ReflectionMethod;
20
use ReflectionParameter;
21
22
use function sprintf;
23
use function usort;
24
25
/**
26
 * @since 3.0.0
27
 */
28
final class ParameterResolverChain implements ParameterResolverChainInterface
29
{
30
    private mixed $context = null;
31
32
    private bool $isSorted = false;
33
34 8
    public function __construct(
35
        /** @var array<array-key, ParameterResolverInterface> */
36
        private array $resolvers = [],
37
    ) {
38 8
    }
39
40 2
    public function withContext(mixed $context): static
41
    {
42 2
        $clone = clone $this;
43 2
        $clone->context = $context;
44
45 2
        return $clone;
46
    }
47
48 2
    public function withResolver(ParameterResolverInterface ...$resolvers): static
49
    {
50 2
        $clone = clone $this;
51 2
        $clone->isSorted = false;
52 2
        foreach ($resolvers as $resolver) {
53 2
            $clone->resolvers[] = $resolver;
54
        }
55
56 2
        return $clone;
57
    }
58
59
    /**
60
     * @inheritDoc
61
     *
62
     * @throws InvalidArgumentException
63
     * @throws LogicException
64
     */
65 5
    public function resolveParameters(ReflectionParameter ...$parameters): Generator
66
    {
67 5
        $this->isSorted or $this->sortResolvers();
68 5
        foreach ($parameters as $parameter) {
69 5
            yield from $this->resolveParameter($parameter);
70
        }
71
    }
72
73
    /**
74
     * @return Generator<int, mixed>
75
     *
76
     * @throws InvalidArgumentException
77
     * @throws LogicException
78
     */
79 5
    private function resolveParameter(ReflectionParameter $parameter): Generator
80
    {
81 5
        foreach ($this->resolvers as $resolver) {
82 4
            $arguments = $resolver->resolveParameter($parameter, $this->context);
83 4
            if ($arguments->valid()) {
84 4
                return yield from $arguments;
85
            }
86
        }
87
88 1
        throw new LogicException(sprintf(
89 1
            'The parameter "%s" is not supported and cannot be resolved.',
90 1
            self::stringifyParameter($parameter),
91 1
        ));
92
    }
93
94 5
    private function sortResolvers(): void
95
    {
96 5
        $this->isSorted = usort($this->resolvers, static fn(
97 5
            ParameterResolverInterface $a,
98 5
            ParameterResolverInterface $b,
99 5
        ): int => $b->getWeight() <=> $a->getWeight());
100
    }
101
102 6
    public static function stringifyParameter(ReflectionParameter $parameter): string
103
    {
104 6
        $function = $parameter->getDeclaringFunction();
105 6
        $position = $parameter->getPosition();
106
107 6
        if ($function instanceof ReflectionMethod) {
108 5
            return sprintf('%s::%s($%s[%d])', $function->class, $function->name, $parameter->name, $position);
109
        }
110
111 1
        return sprintf('%s($%s[%d])', $function->name, $parameter->name, $position);
112
    }
113
}
114