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

AopCode::__invoke()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
cc 2
nc 2
nop 2
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\Node\Expr\Assign;
10
use PhpParser\Node\Scalar;
11
use Ray\Di\Dependency;
12
use Ray\Di\Name;
13
14
use function array_merge;
15
use function array_splice;
16
use function is_array;
17
18
final class AopCode
19
{
20
    /** @var PrivateProperty */
21
    private $privateProperty;
22
23
    public function __construct(PrivateProperty $privateProperty)
24
    {
25
        $this->privateProperty = $privateProperty;
26
    }
27
28
    /**
29
     * Add aop factory code if bindings are given
30
     *
31
     * @param array<Expr> $node
32
     *
33
     * @param-out array<Expr|mixed> $node
34
     */
35
    public function __invoke(Dependency $dependency, array &$node): void
36
    {
37
        $prop = $this->privateProperty;
38
        $newInstance = $prop($dependency, 'newInstance');
39
        $bind = $prop($newInstance, 'bind');
40
        $bind = $prop($bind, 'bind');
41
        /** @var string[][]|null $bindings */
42
        $bindings = $prop($bind, 'bindings', null);
43
        if (! is_array($bindings)) {
44
            return;
45
        }
46
47
        $methodBinding = $this->getMethodBinding($bindings);
48
        $bindingsProp = new Expr\PropertyFetch(new Expr\Variable('instance'), 'bindings');
49
        $bindingsAssign = new Assign($bindingsProp, new Expr\Array_($methodBinding));
50
        $this->setBindingAssignAfterInitialization($node, [$bindingsAssign], 1);
51
    }
52
53
    /**
54
     * @param array<Expr>   $array
55
     * @param array<Assign> $insertValue
56
     *
57
     * @param-out array<Expr|mixed> $array
58
     */
59
    private function setBindingAssignAfterInitialization(array &$array, array $insertValue, int $position): void
60
    {
61
        $array = array_merge(array_splice($array, 0, $position), $insertValue, $array);
62
    }
63
64
    /**
65
     * @param string[][] $bindings
66
     *
67
     * @return Expr\ArrayItem[]
68
     */
69
    private function getMethodBinding(array $bindings): array
70
    {
71
        $methodBinding = [];
72
        foreach ($bindings as $method => $interceptors) {
73
            $items = [];
74
            foreach ($interceptors as $interceptor) {
75
                // $singleton('FakeAopInterface-*');
76
                $dependencyIndex = "{$interceptor}-" . Name::ANY;
77
                $singleton = new Expr\FuncCall(new Expr\Variable('singleton'), [new Node\Arg(new Scalar\String_($dependencyIndex))]);
78
                // [$singleton('FakeAopInterface-*'), $singleton('FakeAopInterface-*');]
79
                $items[] = new Expr\ArrayItem($singleton);
80
            }
81
82
            $arr = new Expr\Array_($items);
83
            $methodBinding[] = new Expr\ArrayItem($arr, new Scalar\String_($method));
84
        }
85
86
        return $methodBinding;
87
    }
88
}
89