Completed
Push — refactor ( 1ac315 )
by Akihito
05:56
created

FunctionCode::getInjectionProviderParams()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Compiler;
6
7
use Doctrine\Common\Annotations\AnnotationReader;
8
use LogicException;
9
use PhpParser\Node;
10
use PhpParser\Node\Expr;
11
use PhpParser\Node\Scalar;
12
use Ray\Di\Argument;
13
use Ray\Di\Container;
14
use Ray\Di\DependencyInterface;
15
use Ray\Di\DependencyProvider;
16
use Ray\Di\Di\Qualifier;
17
use ReflectionClass;
18
use ReflectionMethod;
19
use ReflectionParameter;
20
21
use function assert;
22
23
final class FunctionCode
24
{
25
    /** @var Container */
26
    private $container;
27
28
    /** @var PrivateProperty */
29
    private $privateProperty;
30
31
    /** @var AnnotationReader */
32
    private $reader;
33
34
    /** @var DependencyCode */
35
    private $compiler;
36
37
    public function __construct(Container $container, PrivateProperty $privateProperty, DependencyCode $compiler)
38
    {
39
        $this->container = $container;
40
        $this->privateProperty = $privateProperty;
41
        $this->reader = new AnnotationReader();
42
        $this->compiler = $compiler;
43
    }
44
45
    /**
46
     * Return arguments code for "$singleton" and "$prototype"
47
     */
48
    public function __invoke(Argument $argument, DependencyInterface $dependency): Expr\FuncCall
49
    {
50
        $prop = $this->privateProperty;
51
        $isSingleton = $prop($dependency, 'isSingleton');
52
        $func = $isSingleton ? 'singleton' : 'prototype';
53
        $args = $this->getInjectionFuncParams($argument);
54
55
        /** @var array<Node\Arg> $args */
56
        return new Expr\FuncCall(new Expr\Variable($func), $args);
57
    }
58
59
    /**
60
     * Return dependency index argument
61
     *
62
     * [class, method, param] is added if dependency is provider for DI context
63
     *
64
     * @return array<int, Node\Arg|Node\Expr\Array_>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, 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...
65
     */
66
    private function getInjectionFuncParams(Argument $argument): array
67
    {
68
        $dependencyIndex = (string) $argument;
69
        if ($this->container->getContainer()[$dependencyIndex] instanceof DependencyProvider) {
70
            return $this->getInjectionProviderParams($argument);
71
        }
72
73
        return [new Node\Arg(new Scalar\String_((string) $argument))];
74
    }
75
76
    /**
77
     * Return code for provider
78
     *
79
     * "$provider" needs [class, method, parameter] for InjectionPoint (Contextual Dependency Injection)
80
     *
81
     * @return array<int, Expr\Array_|Node\Arg>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, 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...
82
     */
83
    private function getInjectionProviderParams(Argument $argument): array
84
    {
85
        $param = $argument->get();
86
        $class = $param->getDeclaringClass();
87
        if (! $class instanceof ReflectionClass) {
88
            throw new LogicException(); // @codeCoverageIgnore
89
        }
90
91
        $method = $param->getDeclaringFunction();
92
        assert($method instanceof ReflectionMethod);
93
        $this->setQualifiers($method, $param);
94
95
        return [
96
            new Node\Arg(new Scalar\String_((string) $argument)),
97
            new Expr\Array_([
98
                new Expr\ArrayItem(new Scalar\String_($class->name)),
99
                new Expr\ArrayItem(new Scalar\String_($method->name)),
100
                new Expr\ArrayItem(new Scalar\String_($param->name)),
101
            ]),
102
        ];
103
    }
104
105
    private function setQualifiers(ReflectionMethod $method, ReflectionParameter $param): void
106
    {
107
        $annotations = $this->reader->getMethodAnnotations($method);
108
        foreach ($annotations as $annotation) {
109
            $qualifier = $this->reader->getClassAnnotation(
110
                new ReflectionClass($annotation),
111
                'Ray\Di\Di\Qualifier'
112
            );
113
            if ($qualifier instanceof Qualifier) {
114
                $this->compiler->setQaulifier(new IpQualifier($param, $annotation));
115
            }
116
        }
117
    }
118
}
119