Completed
Pull Request — 2.x (#195)
by Akihito
01:51
created

Bind::in()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 6
cts 6
cp 1
rs 9.9
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 4
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 93
    public function __construct(Container $container, string $interface)
44
    {
45 93
        $this->container = $container;
46 93
        $this->interface = $interface;
47 93
        $this->validate = new BindValidator;
48 93
        $bindUntarget = class_exists($interface) && ! (new \ReflectionClass($interface))->isAbstract() && ! $this->isRegistered($interface);
49 93
        if ($bindUntarget) {
50 50
            $this->untarget = new Untarget($interface);
51
52 50
            return;
53
        }
54 92
        $this->validate->constructor($interface);
55 91
    }
56
57 87
    public function __destruct()
58
    {
59 87
        if ($this->untarget) {
60 43
            ($this->untarget)($this->container, $this);
61 43
            $this->untarget = null;
62
        }
63 87
    }
64
65 87
    public function __toString()
66
    {
67 87
        return $this->interface . '-' . $this->name;
68
    }
69
70
    /**
71
     * Set dependency name
72
     */
73 31
    public function annotatedWith(string $name) : self
74
    {
75 31
        $this->name = $name;
76
77 31
        return $this;
78
    }
79
80
    /**
81
     * Bind to class
82
     */
83 61
    public function to(string $class) : self
84
    {
85 61
        $this->untarget = null;
86 61
        $refClass = $this->validate->to($this->interface, $class);
87 59
        $this->bound = (new DependencyFactory)->newAnnotatedDependency($refClass);
88 59
        $this->container->add($this);
89
90 59
        return $this;
91
    }
92
93
    /**
94
     * Bind to constructor
95
     *
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 4
    public function toConstructor(string $class, $name, InjectionPoints $injectionPoints = null, string $postConstruct = null) : self
102
    {
103 4
        if (\is_array($name)) {
104 1
            $name = $this->getStringName($name);
105
        }
106 4
        $this->untarget = null;
107 4
        $postConstructRef = $postConstruct ? (new NewReflectionMethod)($class, $postConstruct) : null;
108 4
        $this->bound = (new DependencyFactory)->newToConstructor((new NewReflectionClass)($class), $name, $injectionPoints, $postConstructRef);
109 4
        $this->container->add($this);
110
111 4
        return $this;
112
    }
113
114
    /**
115
     * Bind to provider
116
     */
117 50
    public function toProvider(string $provider, string $context = '') : self
118
    {
119 50
        $this->untarget = null;
120 50
        $refClass = $this->validate->toProvider($provider);
121 48
        $this->bound = (new DependencyFactory)->newProvider($refClass, $context);
122 48
        $this->container->add($this);
123
124 48
        return $this;
125
    }
126
127
    /**
128
     * Bind to instance
129
     */
130 80
    public function toInstance($instance) : self
131
    {
132 80
        $this->untarget = null;
133 80
        $this->bound = new Instance($instance);
134 80
        $this->container->add($this);
135
136 80
        return $this;
137
    }
138
139
    /**
140
     * Set scope
141
     */
142 46
    public function in(string $scope) : self
143
    {
144 46
        if ($this->bound instanceof Dependency || $this->bound instanceof DependencyProvider) {
145 45
            $this->bound->setScope($scope);
146
        }
147 46
        if ($this->untarget) {
148 41
            $this->untarget->setScope($scope);
149
        }
150
151 46
        return $this;
152
    }
153
154 86
    public function getBound() : DependencyInterface
155
    {
156 86
        return $this->bound;
157
    }
158
159 43
    public function setBound(DependencyInterface $bound)
160
    {
161 43
        $this->bound = $bound;
162 43
    }
163
164 50
    private function isRegistered(string $interface) : bool
165
    {
166 50
        return isset($this->container->getContainer()[$interface . '-' . Name::ANY]);
167
    }
168
169
    /**
170
     * Return string
171
     *
172
     * input: [['varA' => 'nameA'], ['varB' => 'nameB']]
173
     * output: "varA=nameA,varB=nameB"
174
     */
175
    private function getStringName(array $name) : string
176
    {
177 1
        $names = array_reduce(array_keys($name), function (array $carry, string $key) use ($name) : array {
178 1
            $carry[] = $key . '=' . $name[$key];
179
180 1
            return $carry;
181 1
        }, []);
182
183 1
        return implode(',', $names);
184
    }
185
}
186