Completed
Push — with-args ( 95d9fd )
by Akihito
01:35
created

Container   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

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

13 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 10 2
A getDependency() 0 9 2
A move() 0 10 2
A unbound() 0 9 3
A getContainer() 0 4 1
A getPointcuts() 0 4 1
A merge() 0 5 1
A weaveAspects() 0 9 3
A weaveAspect() 0 6 1
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;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Ray\Di\Pointcut.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use Ray\Di\Exception\Unbound;
11
use Ray\Di\Exception\Untargeted;
12
13
final class Container
14
{
15
    /**
16
     * @var Dependency[]
17
     */
18
    private $container = [];
19
20
    /**
21
     * @var Pointcut[]
22
     */
23
    private $pointcuts = [];
24
25
    public function __sleep()
26
    {
27
        return ['container', 'pointcuts'];
28
    }
29
30
    /**
31
     * Add binding to container
32
     */
33
    public function add(Bind $bind)
34
    {
35
        $dependency = $bind->getBound();
36
        $dependency->register($this->container, $bind);
37
    }
38
39
    /**
40
     * Add Pointcut to container
41
     */
42
    public function addPointcut(Pointcut $pointcut)
43
    {
44
        $this->pointcuts[] = $pointcut;
45
    }
46
47
    /**
48
     * Return instance by interface + name(interface namespace)
49
     */
50
    public function getInstance(string $interface, string $name)
51
    {
52
        return $this->getDependency($interface . '-' . $name);
53
    }
54
55
    /**
56
     * Return dependency injected instance
57
     *
58
     * @throws Unbound
59
     */
60
    public function getInstanceWithArgs(string $interface, string $name, array $params)
61
    {
62
        $index = $interface . '-' . $name;
63
        if (! isset($this->container[$index])) {
64
            throw $this->unbound($index);
65
        }
66
        $dependency = $this->container[$index];
67
68
        return $dependency->injectWithArgs($this, $params);
69
    }
70
71
    /**
72
     * Return dependency injected instance
73
     *
74
     * @throws Unbound
75
     */
76
    public function getDependency(string $index)
77
    {
78
        if (! isset($this->container[$index])) {
79
            throw $this->unbound($index);
80
        }
81
        $dependency = $this->container[$index];
82
83
        return $dependency->inject($this);
84
    }
85
86
    /**
87
     * Rename existing dependency interface + name
88
     */
89
    public function move(string $sourceInterface, string $sourceName, string $targetInterface, string $targetName)
90
    {
91
        $sourceIndex = $sourceInterface . '-' . $sourceName;
92
        if (! isset($this->container[$sourceIndex])) {
93
            throw $this->unbound($sourceIndex);
94
        }
95
        $targetIndex = $targetInterface . '-' . $targetName;
96
        $this->container[$targetIndex] = $this->container[$sourceIndex];
97
        unset($this->container[$sourceIndex]);
98
    }
99
100
    /**
101
     * Return Unbound exception
102
     *
103
     * @param string $index {interface}-{bind name}
104
     *
105
     * @return Unbound|Untargeted
106
     */
107
    public function unbound(string $index)
108
    {
109
        list($class, $name) = explode('-', $index);
110
        if (class_exists($class) && ! (new \ReflectionClass($class))->isAbstract()) {
111
            return new Untargeted($class);
112
        }
113
114
        return new Unbound("{$class}-{$name}");
115
    }
116
117
    /**
118
     * Return container
119
     *
120
     * @return Dependency[]
121
     */
122
    public function getContainer() : array
123
    {
124
        return $this->container;
125
    }
126
127
    /**
128
     * Return pointcuts
129
     *
130
     * @return Pointcut[]
131
     */
132
    public function getPointcuts() : array
133
    {
134
        return $this->pointcuts;
135
    }
136
137
    /**
138
     * Merge container
139
     */
140
    public function merge(self $container)
141
    {
142
        $this->container += $container->getContainer();
143
        $this->pointcuts = array_merge($this->pointcuts, $container->getPointcuts());
144
    }
145
146
    /**
147
     * Weave aspects to all dependency in container
148
     */
149
    public function weaveAspects(CompilerInterface $compiler)
150
    {
151
        foreach ($this->container as $dependency) {
152
            if (! $dependency instanceof Dependency) {
153
                continue;
154
            }
155
            $dependency->weaveAspects($compiler, $this->pointcuts);
156
        }
157
    }
158
159
    /**
160
     * Weave aspect to single dependency
161
     */
162
    public function weaveAspect(Compiler $compiler, Dependency $dependency) : self
163
    {
164
        $dependency->weaveAspects($compiler, $this->pointcuts);
165
166
        return $this;
167
    }
168
}
169