Completed
Pull Request — 2.x (#210)
by Akihito
01:58
created

Container::weaveAspect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Di;
6
7
use Ray\Aop\Compiler;
8
use Ray\Aop\CompilerInterface;
9
use Ray\Aop\Pointcut;
10
use Ray\Di\Exception\Unbound;
11
use Ray\Di\Exception\Untargeted;
12
13
final class Container
14
{
15
    /**
16
     * @var DependencyInterface[]
17
     */
18
    private $container = [];
19
20
    /**
21
     * @var array<int, Pointcut>
22
     */
23
    private $pointcuts = [];
24
25 4
    public function __sleep()
26
    {
27 4
        return ['container', 'pointcuts'];
28
    }
29
30
    /**
31
     * Add binding to container
32
     */
33 86
    public function add(Bind $bind) : void
34
    {
35 86
        $dependency = $bind->getBound();
36 86
        $dependency->register($this->container, $bind);
37 86
    }
38
39
    /**
40
     * Add Pointcut to container
41
     */
42 42
    public function addPointcut(Pointcut $pointcut) : void
43
    {
44 42
        $this->pointcuts[] = $pointcut;
45 42
    }
46
47
    /**
48
     * Return instance by interface + name(interface namespace)
49
     *
50 53
     * @param class-string|string $interface
0 ignored issues
show
Documentation introduced by
The doc-type class-string|string could not be parsed: Unknown type name "class-string" at position 0. (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...
51
     *
52 53
     * @return mixed
53
     */
54
    public function getInstance(string $interface, string $name)
55
    {
56
        return $this->getDependency($interface . '-' . $name);
57
    }
58
59
    /**
60 73
     * Return dependency injected instance
61
     *
62 73
     * @param array<int, mixed> $params
63 28
     *
64
     * @throws Unbound
65 69
     *
66
     * @return mixed
67 69
     */
68
    public function getInstanceWithArgs(string $interface, array $params)
69
    {
70
        $index = $interface . '-';
71
        if (! isset($this->container[$index])) {
72
            throw $this->unbound($index);
73 3
        }
74
        $dependency = $this->container[$index];
75 3
        if (! $dependency instanceof Dependency) {
76 3
            throw new \BadMethodCallException($interface);
77 1
        }
78
79 2
        return $dependency->injectWithArgs($this, $params);
80 2
    }
81 2
82 2
    /**
83
     * Return dependency injected instance
84
     *
85
     * @throws Unbound
86
     *
87
     * @return mixed
88
     */
89
    public function getDependency(string $index)
90
    {
91 29
        $dependency = $this->container[$index] ?? $this->getParentDependency($index);
92
93 29
        return $dependency->inject($this);
94 29
    }
95 16
96
    /**
97
     * Rename existing dependency interface + name
98 16
     */
99
    public function move(string $sourceInterface, string $sourceName, string $targetInterface, string $targetName) : void
100
    {
101
        $sourceIndex = $sourceInterface . '-' . $sourceName;
102
        if (! isset($this->container[$sourceIndex])) {
103
            throw $this->unbound($sourceIndex);
104
        }
105
        $targetIndex = $targetInterface . '-' . $targetName;
106 56
        $this->container[$targetIndex] = $this->container[$sourceIndex];
107
        unset($this->container[$sourceIndex]);
108 56
    }
109
110
    /**
111
     * Return Unbound exception
112
     *
113
     * @param string $index {interface}-{bind name}
114
     *
115
     * @return Unbound|Untargeted
116 45
     */
117
    public function unbound(string $index)
118 45
    {
119
        [$class, $name] = explode('-', $index);
0 ignored issues
show
Bug introduced by
The variable $class does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $name does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
120
        if (class_exists($class) && ! (new \ReflectionClass($class))->isAbstract()) {
121
            return new Untargeted($class);
122
        }
123
124 44
        return new Unbound("{$class}-{$name}");
125
    }
126 44
127 44
    /**
128 44
     * Return container
129
     *
130
     * @return DependencyInterface[]
131
     */
132
    public function getContainer() : array
133 40
    {
134
        return $this->container;
135 40
    }
136 40
137 40
    /**
138
     * Return pointcuts
139 40
     *
140
     * @return array<int, Pointcut>
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...
141 40
     */
142
    public function getPointcuts() : array
143
    {
144
        return $this->pointcuts;
145
    }
146 16
147
    /**
148 16
     * Merge container
149
     */
150 16
    public function merge(self $container) : void
151
    {
152
        $this->container += $container->getContainer();
153
        $this->pointcuts = array_merge($this->pointcuts, $container->getPointcuts());
154
    }
155
156
    /**
157
     * Weave aspects to all dependency in container
158
     */
159
    public function weaveAspects(CompilerInterface $compiler) : void
160
    {
161
        foreach ($this->container as $dependency) {
162
            if (! $dependency instanceof Dependency) {
163
                continue;
164
            }
165
            $dependency->weaveAspects($compiler, $this->pointcuts);
166
        }
167
    }
168
169
    /**
170
     * Weave aspect to single dependency
171
     */
172
    public function weaveAspect(Compiler $compiler, Dependency $dependency) : self
173
    {
174
        $dependency->weaveAspects($compiler, $this->pointcuts);
175
176
        return $this;
177
    }
178
179
    private function getParentDependency(string $index) : DependencyInterface
180
    {
181
        [$class] = explode('-', $index);
0 ignored issues
show
Bug introduced by
The variable $class does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
182
        if (! class_exists($class)) {
183
            throw $this->unbound($index);
184
        }
185
        $parent = (new \ReflectionClass($class))->getParentClass();
186
        if (! $parent) {
187
            throw $this->unbound($index);
188
        }
189
        $parentIndex = $parent->getName() . '-';
190
        if (isset($this->container[$parentIndex])) {
191
            return $this->container[$parentIndex];
192
        }
193
194
        return $this->getParentDependency($parentIndex);
195
    }
196
}
197