Completed
Push — param-inject ( c05762...050acd )
by Akihito
01:14
created

ParamInjectInterceptor::getNamedArguments()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Di;
6
7
use Ray\Aop\MethodInterceptor;
8
use Ray\Aop\MethodInvocation;
9
use Ray\Di\Di\Inject;
10
use Ray\Di\Di\Named;
11
use ReflectionAttribute;
12
use ReflectionNamedType;
13
use ReflectionParameter;
14
15
use function assert;
16
use function call_user_func_array;
17
use function is_callable;
18
19
final class ParamInjectInterceptor implements MethodInterceptor
20
{
21
    /** @var InjectorInterface */
22
    private $injector;
23
24
    /** @var MethodInvocationProvider */
25
    private $methodInvocationProvider;
26
27
    public function __construct(InjectorInterface $injector, MethodInvocationProvider $methodInvocationProvider)
28
    {
29
        $this->injector = $injector;
30
        $this->methodInvocationProvider = $methodInvocationProvider;
31
    }
32
33
    /**
34
     * @return mixed
35
     */
36
    public function invoke(MethodInvocation $invocation)
37
    {
38
        $this->methodInvocationProvider->set($invocation);
39
        $params = $invocation->getMethod()->getParameters();
40
        $namedArguments = $this->getNamedArguments($invocation);
41
        foreach ($params as $param) {
42
            /** @var list<ReflectionAttribute> $attributes */
0 ignored issues
show
Documentation introduced by
The doc-type list<ReflectionAttribute> could not be parsed: Expected "|" or "end of type", but got "<" at position 4. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
43
            $attributes = $param->getAttributes(Inject::class);
44
            if (isset($attributes[0])) {
45
                /** @psalm-suppress MixedAssignment */
46
                $namedArguments[$param->getName()] = $this->getDependency($param);
0 ignored issues
show
Bug introduced by
Consider using $param->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
47
            }
48
        }
49
50
        $callable = [$invocation->getThis(), $invocation->getMethod()->getName()];
0 ignored issues
show
Bug introduced by
Consider using $invocation->getMethod()->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
51
        assert(is_callable($callable));
52
53
        return call_user_func_array($callable, $namedArguments); // @phpstan-ignore-line PHP8 named arguments
54
    }
55
56
    /**
57
     * @return array<string, mixed>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
58
     */
59
    private function getNamedArguments(MethodInvocation $invocation): array
60
    {
61
        $args = $invocation->getArguments();
62
        $params = $invocation->getMethod()->getParameters();
63
        $namedParams = [];
64
        foreach ($params as $param) {
65
            $pos = $param->getPosition();
66
            if (isset($args[$pos])) {
67
                /** @psalm-suppress MixedAssignment */
68
                $namedParams[$param->getName()] = $args[$pos];
0 ignored issues
show
Bug introduced by
Consider using $param->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
69
            }
70
        }
71
72
        return $namedParams;
73
    }
74
75
    /**
76
     * @return mixed
77
     */
78
    private function getDependency(ReflectionParameter $param)
79
    {
80
        $named = $this->getName($param);
81
        $type = $param->getType();
82
        assert($type instanceof ReflectionNamedType || $type === null);
0 ignored issues
show
Bug introduced by
The class ReflectionNamedType does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
83
        $interface = $type ? $type->getName() : '';
84
85
        return $this->injector->getInstance($interface, $named);
86
    }
87
88
    private function getName(ReflectionParameter $param): string
89
    {
90
        /** @var list<ReflectionAttribute> $attributes */
0 ignored issues
show
Documentation introduced by
The doc-type list<ReflectionAttribute> could not be parsed: Expected "|" or "end of type", but got "<" at position 4. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
91
        $attributes = $param->getAttributes(Named::class);
92
        if (isset($attributes[0])) {
93
            $named = $attributes[0]->newInstance();
94
            assert($named instanceof Named);
95
96
            return $named->value;
97
        }
98
99
        return '';
100
    }
101
}
102