Completed
Pull Request — 2.x (#216)
by Akihito
09:22
created

FunctionCode::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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