Completed
Push — 2.x ( 8f6930...447f85 )
by Akihito
01:14
created

Container   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
wmc 23
lcom 2
cbo 5
dl 0
loc 180
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __sleep() 0 4 1
A add() 0 5 1
A addPointcut() 0 4 1
A getInstance() 0 4 1
A getInstanceWithArgs() 0 14 3
A getDependency() 0 10 2
A move() 0 11 2
A unbound() 0 9 3
A getContainer() 0 4 1
A getPointcuts() 0 4 1
A merge() 0 5 1
A weaveAspects() 0 8 3
A weaveAspect() 0 6 1
A map() 0 6 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Di;
6
7
use BadMethodCallException;
8
use Ray\Aop\Compiler;
9
use Ray\Aop\CompilerInterface;
10
use Ray\Aop\Pointcut;
11
use Ray\Di\Exception\Unbound;
12
use Ray\Di\Exception\Untargeted;
13
use ReflectionClass;
14
15
use function array_merge;
16
use function class_exists;
17
use function explode;
18
19
final class Container
20
{
21
    /** @var DependencyInterface[] */
22
    private $container = [];
23
24
    /** @var array<int, Pointcut> */
25
    private $pointcuts = [];
26
27
    /**
28
     * @return list<string>
0 ignored issues
show
Documentation introduced by
The doc-type list<string> could not be parsed: Expected "|" or "end of type", but got "<" at position 4. (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...
29
     */
30
    public function __sleep()
31
    {
32
        return ['container', 'pointcuts'];
33
    }
34
35
    /**
36
     * Add binding to container
37
     */
38
    public function add(Bind $bind): void
39
    {
40
        $dependency = $bind->getBound();
41
        $dependency->register($this->container, $bind);
42
    }
43
44
    /**
45
     * Add Pointcut to container
46
     */
47
    public function addPointcut(Pointcut $pointcut): void
48
    {
49
        $this->pointcuts[] = $pointcut;
50
    }
51
52
    /**
53
     * Return instance by interface + name(interface namespace)
54
     *
55
     * @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...
56
     *
57
     * @return mixed
58
     */
59
    public function getInstance(string $interface, string $name)
60
    {
61
        return $this->getDependency($interface . '-' . $name);
62
    }
63
64
    /**
65
     * Return dependency injected instance
66
     *
67
     * @param array<int, mixed> $params
68
     *
69
     * @return mixed
70
     *
71
     * @throws Unbound
72
     */
73
    public function getInstanceWithArgs(string $interface, array $params)
74
    {
75
        $index = $interface . '-';
76
        if (! isset($this->container[$index])) {
77
            throw $this->unbound($index);
78
        }
79
80
        $dependency = $this->container[$index];
81
        if (! $dependency instanceof Dependency) {
82
            throw new BadMethodCallException($interface);
83
        }
84
85
        return $dependency->injectWithArgs($this, $params);
86
    }
87
88
    /**
89
     * Return dependency injected instance
90
     *
91
     * @return mixed
92
     *
93
     * @throws Unbound
94
     */
95
    public function getDependency(string $index)
96
    {
97
        if (! isset($this->container[$index])) {
98
            throw $this->unbound($index);
99
        }
100
101
        $dependency = $this->container[$index];
102
103
        return $dependency->inject($this);
104
    }
105
106
    /**
107
     * Rename existing dependency interface + name
108
     */
109
    public function move(string $sourceInterface, string $sourceName, string $targetInterface, string $targetName): void
110
    {
111
        $sourceIndex = $sourceInterface . '-' . $sourceName;
112
        if (! isset($this->container[$sourceIndex])) {
113
            throw $this->unbound($sourceIndex);
114
        }
115
116
        $targetIndex = $targetInterface . '-' . $targetName;
117
        $this->container[$targetIndex] = $this->container[$sourceIndex];
118
        unset($this->container[$sourceIndex]);
119
    }
120
121
    /**
122
     * Return Unbound exception
123
     *
124
     * @param string $index {interface}-{bind name}
125
     *
126
     * @return Unbound|Untargeted
127
     */
128
    public function unbound(string $index)
129
    {
130
        [$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...
131
        if (class_exists($class) && ! (new ReflectionClass($class))->isAbstract()) {
132
            return new Untargeted($class);
133
        }
134
135
        return new Unbound("{$class}-{$name}");
136
    }
137
138
    /**
139
     * Return container
140
     *
141
     * @return DependencyInterface[]
142
     */
143
    public function getContainer(): array
144
    {
145
        return $this->container;
146
    }
147
148
    /**
149
     * Return pointcuts
150
     *
151
     * @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...
152
     */
153
    public function getPointcuts(): array
154
    {
155
        return $this->pointcuts;
156
    }
157
158
    /**
159
     * Merge container
160
     */
161
    public function merge(self $container): void
162
    {
163
        $this->container += $container->getContainer();
164
        $this->pointcuts = array_merge($this->pointcuts, $container->getPointcuts());
165
    }
166
167
    /**
168
     * Weave aspects to all dependency in container
169
     */
170
    public function weaveAspects(CompilerInterface $compiler): void
171
    {
172
        foreach ($this->container as $dependency) {
173
            if ($dependency instanceof Dependency) {
174
                $dependency->weaveAspects($compiler, $this->pointcuts);
175
            }
176
        }
177
    }
178
179
    /**
180
     * Weave aspect to single dependency
181
     */
182
    public function weaveAspect(Compiler $compiler, Dependency $dependency): self
183
    {
184
        $dependency->weaveAspects($compiler, $this->pointcuts);
185
186
        return $this;
187
    }
188
189
    /**
190
     * @param callable(DependencyInterface): DependencyInterface $f
191
     */
192
    public function map(callable $f): void
193
    {
194
        foreach ($this->container as &$index) {
195
            $index = $f($index);
196
        }
197
    }
198
}
199