Completed
Push — 2.x ( 39dc4e...b7fd10 )
by Akihito
01:28
created

Bind   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 22
lcom 2
cbo 7
dl 0
loc 179
ccs 59
cts 59
cp 1
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 4
A __destruct() 0 7 2
A __toString() 0 4 1
A toProvider() 0 9 1
A toInstance() 0 8 1
A setBound() 0 4 1
A isRegistered() 0 4 1
A annotatedWith() 0 6 1
A to() 0 9 1
A toConstructor() 0 12 3
A in() 0 11 4
A getBound() 0 4 1
A getStringName() 0 10 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Di;
6
7
final class Bind
8
{
9
    /**
10
     * @var Container
11
     */
12
    private $container;
13
14
    /**
15
     * @var string
16
     */
17
    private $interface;
18
19
    /**
20
     * @var string
21
     */
22
    private $name = Name::ANY;
23
24
    /**
25
     * @var DependencyInterface
26
     */
27
    private $bound;
28
29
    /**
30
     * @var BindValidator
31
     */
32
    private $validate;
33
34
    /**
35
     * @var null|Untarget
36
     */
37
    private $untarget;
38
39
    /**
40
     * @param Container $container dependency container
41
     * @param string    $interface interface or concrete class name
42
     */
43
    public function __construct(Container $container, string $interface)
44
    {
45
        $this->container = $container;
46
        $this->interface = $interface;
47
        $this->validate = new BindValidator;
48 93
        $bindUntarget = class_exists($interface) && ! (new \ReflectionClass($interface))->isAbstract() && ! $this->isRegistered($interface);
49
        if ($bindUntarget) {
50 93
            $this->untarget = new Untarget($interface);
51 93
52 93
            return;
53 93
        }
54 93
        $this->validate->constructor($interface);
55 50
    }
56
57 50
    public function __destruct()
58
    {
59 92
        if ($this->untarget) {
60 91
            ($this->untarget)($this->container, $this);
61
            $this->untarget = null;
62 87
        }
63
    }
64 87
65 43
    public function __toString()
66 43
    {
67
        return $this->interface . '-' . $this->name;
68 87
    }
69
70 87
    /**
71
     * Set dependency name
72 87
     */
73
    public function annotatedWith(string $name) : self
74
    {
75
        $this->name = $name;
76
77
        return $this;
78 31
    }
79
80 31
    /**
81
     * Bind to class
82 31
     */
83
    public function to(string $class) : self
84
    {
85
        $this->untarget = null;
86
        $refClass = $this->validate->to($this->interface, $class);
87
        $this->bound = (new DependencyFactory)->newAnnotatedDependency($refClass);
88 61
        $this->container->add($this);
89
90 61
        return $this;
91 61
    }
92 59
93 59
    /**
94
     * Bind to constructor
95 59
     *
96
     * @param string          $class           class name
97
     * @param string | array  $name            "varName=bindName,..." or [[$varName => $bindName],[$varName => $bindName]...]
98
     * @param InjectionPoints $injectionPoints injection points
99
     * @param string          $postConstruct   method name of initialization after all dependencies are injected*
100
     */
101
    public function toConstructor(string $class, $name, InjectionPoints $injectionPoints = null, string $postConstruct = null) : self
102
    {
103
        if (\is_array($name)) {
104
            $name = $this->getStringName($name);
105
        }
106 4
        $this->untarget = null;
107
        $postConstructRef = $postConstruct ? (new NewReflectionMethod)($class, $postConstruct) : null;
108 4
        $this->bound = (new DependencyFactory)->newToConstructor((new NewReflectionClass)($class), $name, $injectionPoints, $postConstructRef);
109 1
        $this->container->add($this);
110
111 4
        return $this;
112 4
    }
113 4
114 4
    /**
115
     * Bind to provider
116 4
     */
117
    public function toProvider(string $provider, string $context = '') : self
118
    {
119
        $this->untarget = null;
120
        $refClass = $this->validate->toProvider($provider);
121
        $this->bound = (new DependencyFactory)->newProvider($refClass, $context);
122 50
        $this->container->add($this);
123
124 50
        return $this;
125 50
    }
126 48
127 48
    /**
128
     * Bind to instance
129 48
     */
130
    public function toInstance($instance) : self
131
    {
132
        $this->untarget = null;
133
        $this->bound = new Instance($instance);
134
        $this->container->add($this);
135
136
        return $this;
137 80
    }
138
139 80
    /**
140 80
     * Set scope
141 80
     */
142
    public function in(string $scope) : self
143 80
    {
144
        if ($this->bound instanceof Dependency || $this->bound instanceof DependencyProvider) {
145
            $this->bound->setScope($scope);
146
        }
147
        if ($this->untarget) {
148
            $this->untarget->setScope($scope);
149 46
        }
150
151 46
        return $this;
152 45
    }
153
154 46
    public function getBound() : DependencyInterface
155 41
    {
156
        return $this->bound;
157
    }
158 46
159
    public function setBound(DependencyInterface $bound)
160
    {
161 86
        $this->bound = $bound;
162
    }
163 86
164
    private function isRegistered(string $interface) : bool
165
    {
166 43
        return isset($this->container->getContainer()[$interface . '-' . Name::ANY]);
167
    }
168 43
169 43
    /**
170
     * Return string
171 50
     *
172
     * input: [['varA' => 'nameA'], ['varB' => 'nameB']]
173 50
     * output: "varA=nameA,varB=nameB"
174
     */
175 50
    private function getStringName(array $name) : string
176
    {
177
        $names = array_reduce(array_keys($name), function (array $carry, string $key) use ($name) : array {
178
            $carry[] = $key . '=' . $name[$key];
179
180
            return $carry;
181
        }, []);
182
183
        return implode(',', $names);
184
    }
185
}
186