Passed
Pull Request — 2.x (#9)
by Akihito
09:28
created

Container::sort()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 0
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
use function ksort;
19
20
final class Container implements InjectorInterface
21
{
22
    /** @var DependencyInterface[] */
23
    private $container = [];
24
25
    /** @var array<int, Pointcut> */
26
    private $pointcuts = [];
27
28
    /**
29
     * @return list<string>
0 ignored issues
show
Bug introduced by
The type Ray\Di\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
     */
31
    public function __sleep()
32
    {
33
        return ['container', 'pointcuts'];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array('container', 'pointcuts') returns the type array<integer,string> which is incompatible with the documented return type Ray\Di\list.
Loading history...
34
    }
35
36
    /**
37
     * Add binding to container
38
     */
39
    public function add(Bind $bind): void
40
    {
41
        $dependency = $bind->getBound();
42
        $dependency->register($this->container, $bind);
43
    }
44
45
    /**
46
     * Add Pointcut to container
47
     */
48
    public function addPointcut(Pointcut $pointcut): void
49
    {
50
        $this->pointcuts[] = $pointcut;
51
    }
52
53
    /**
54
     * {@inheritDoc}
55
     */
56
    public function getInstance($interface, $name = Name::ANY)
57
    {
58
        /**
59
         * @psalm-var T is object ? T : mixed
60
         * @phpstan-var mixed
61
         */
62
        return $this->getDependency($interface . '-' . $name);
63
    }
64
65
    /**
66
     * Return dependency injected instance
67
     *
68
     * @param array<int, mixed> $params
69
     *
70
     * @return mixed
71
     *
72
     * @throws Unbound
73
     */
74
    public function getInstanceWithArgs(string $interface, array $params)
75
    {
76
        $index = $interface . '-';
77
        if (! isset($this->container[$index])) {
78
            throw $this->unbound($index);
79
        }
80
81
        $dependency = $this->container[$index];
82
        if (! $dependency instanceof Dependency) {
83
            throw new BadMethodCallException($interface);
84
        }
85
86
        return $dependency->injectWithArgs($this, $params);
87
    }
88
89
    /**
90
     * Return dependency injected instance
91
     *
92
     * @return mixed
93
     *
94
     * @throws Unbound
95
     */
96
    public function getDependency(string $index)
97
    {
98
        if (! isset($this->container[$index])) {
99
            throw $this->unbound($index);
100
        }
101
102
        $dependency = $this->container[$index];
103
104
        return $dependency->inject($this);
105
    }
106
107
    /**
108
     * Rename existing dependency interface + name
109
     */
110
    public function move(string $sourceInterface, string $sourceName, string $targetInterface, string $targetName): void
111
    {
112
        $sourceIndex = $sourceInterface . '-' . $sourceName;
113
        if (! isset($this->container[$sourceIndex])) {
114
            throw $this->unbound($sourceIndex);
115
        }
116
117
        $targetIndex = $targetInterface . '-' . $targetName;
118
        $this->container[$targetIndex] = $this->container[$sourceIndex];
119
        unset($this->container[$sourceIndex]);
120
    }
121
122
    /**
123
     * Return Unbound exception
124
     *
125
     * @param string $index {interface}-{bind name}
126
     *
127
     * @return Unbound|Untargeted
128
     */
129
    public function unbound(string $index)
130
    {
131
        [$class, $name] = explode('-', $index);
132
        if (class_exists($class) && ! (new ReflectionClass($class))->isAbstract()) {
133
            return new Untargeted($class);
134
        }
135
136
        return new Unbound("{$class}-{$name}");
137
    }
138
139
    /**
140
     * Return container
141
     *
142
     * @return DependencyInterface[]
143
     */
144
    public function getContainer(): array
145
    {
146
        return $this->container;
147
    }
148
149
    /**
150
     * Return pointcuts
151
     *
152
     * @return array<int, Pointcut>
153
     */
154
    public function getPointcuts(): array
155
    {
156
        return $this->pointcuts;
157
    }
158
159
    /**
160
     * Merge container
161
     */
162
    public function merge(self $container): void
163
    {
164
        $this->container += $container->getContainer();
165
        $this->pointcuts = array_merge($this->pointcuts, $container->getPointcuts());
166
    }
167
168
    /**
169
     * Weave aspects to all dependency in container
170
     */
171
    public function weaveAspects(CompilerInterface $compiler): void
172
    {
173
        foreach ($this->container as $dependency) {
174
            if ($dependency instanceof Dependency) {
175
                $dependency->weaveAspects($compiler, $this->pointcuts);
176
            }
177
        }
178
    }
179
180
    /**
181
     * Weave aspect to single dependency
182
     */
183
    public function weaveAspect(Compiler $compiler, Dependency $dependency): self
184
    {
185
        $dependency->weaveAspects($compiler, $this->pointcuts);
186
187
        return $this;
188
    }
189
190
    /**
191
     * @param callable(DependencyInterface): DependencyInterface $f
192
     */
193
    public function map(callable $f): void
194
    {
195
        foreach ($this->container as &$index) {
196
            $index = $f($index);
197
        }
198
    }
199
200
    public function sort(): void
201
    {
202
        ksort($this->container);
203
    }
204
}
205