Completed
Push — spike ( 2414ba )
by Akihito
06:46
created

Container   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Test Coverage

Coverage 78.26%

Importance

Changes 0
Metric Value
wmc 18
lcom 2
cbo 5
dl 0
loc 148
ccs 36
cts 46
cp 0.7826
rs 10
c 0
b 0
f 0

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