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

FactoryCode   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 10
dl 0
loc 99
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A getFactoryCode() 0 18 3
A getArgStmt() 0 19 4
A getConstructorInjection() 0 11 2
A getInjectionPoint() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Compiler;
6
7
use PhpParser\Node;
8
use PhpParser\Node\Expr;
9
use PhpParser\NodeAbstract;
10
use Ray\Di\Argument;
11
use Ray\Di\Container;
12
use Ray\Di\InjectorInterface;
13
use Ray\Di\Instance;
14
use Ray\Di\Name;
15
use Ray\Di\SetterMethod;
16
17
final class FactoryCode
18
{
19
    /** @var Container */
20
    private $container;
21
22
    /** @var Normalizer */
23
    private $normalizer;
24
25
    /** @var NodeFactory */
26
    private $nodeFactory;
27
28
    /** @var FunctionCode */
29
    private $functionCompiler;
30
31
    public function __construct(
32
        Container $container,
33
        Normalizer $normalizer,
34
        DependencyCode $compiler,
35
        ?InjectorInterface $injector = null
36
    ) {
37
        $this->container = $container;
38
        $this->normalizer = $normalizer;
39
        $this->nodeFactory = new NodeFactory($normalizer, $this, $injector);
40
        $this->functionCompiler = new FunctionCode($container, new PrivateProperty(), $compiler);
41
    }
42
43
    /**
44
     * @param array<Argument>     $arguments
45
     * @param array<SetterMethod> $setterMethods
46
     *
47
     * @return array<Expr>
48
     */
49
    public function getFactoryCode(string $class, array $arguments, array $setterMethods, string $postConstruct): array
50
    {
51
        $node = [];
52
        $instance = new Expr\Variable('instance');
53
        // constructor injection
54
        $constructorInjection = $this->getConstructorInjection($class, $arguments);
55
        $node[] = new Expr\Assign($instance, $constructorInjection);
56
        $setters = $this->nodeFactory->getSetterInjection($instance, $setterMethods);
57
        foreach ($setters as $setter) {
58
            $node[] = $setter;
59
        }
60
61
        if ($postConstruct) {
62
            $node[] = $this->nodeFactory->getPostConstruct($instance, $postConstruct);
63
        }
64
65
        return $node;
66
    }
67
68
    /**
69
     * Return method argument code
70
     *
71
     * @return Expr|Expr\FuncCall
72
     */
73
    public function getArgStmt(Argument $argument): NodeAbstract
74
    {
75
        $dependencyIndex = (string) $argument;
76
        if ($dependencyIndex === 'Ray\Di\InjectionPointInterface-' . Name::ANY) {
77
            return $this->getInjectionPoint();
78
        }
79
80
        $hasDependency = isset($this->container->getContainer()[$dependencyIndex]);
81
        if (! $hasDependency) {
82
            return $this->nodeFactory->getNode($argument);
83
        }
84
85
        $dependency = $this->container->getContainer()[$dependencyIndex];
86
        if ($dependency instanceof Instance) {
87
            return ($this->normalizer)($dependency->value);
88
        }
89
90
        return ($this->functionCompiler)($argument, $dependency);
91
    }
92
93
    /**
94
     * @param array<Argument> $arguments
95
     */
96
    private function getConstructorInjection(string $class, array $arguments = []): Expr\New_
97
    {
98
        $args = [];
99
        foreach ($arguments as $argument) {
100
            //            $argument = $argument->isDefaultAvailable() ? $argument->getDefaultValue() : $argument;
101
            $args[] = $this->getArgStmt($argument);
102
        }
103
104
        /** @var array<Node\Arg> $args */
105
        return new Expr\New_(new Node\Name\FullyQualified($class), $args);
106
    }
107
108
    /**
109
     * Return "$injectionPoint()"
110
     */
111
    private function getInjectionPoint(): Expr
112
    {
113
        return new Expr\FuncCall(new Expr\Variable('injectionPoint'));
114
    }
115
}
116