Completed
Push — 4.x ( 8fa263...613328 )
by Phil
03:02
created

Definition   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 208
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 33
lcom 2
cbo 5
dl 0
loc 208
ccs 79
cts 79
cp 1
rs 9.76
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A addTag() 0 5 1
A hasTag() 0 4 1
A setAlias() 0 5 1
A getAlias() 0 4 1
A setShared() 0 5 1
A isShared() 0 4 1
A getConcrete() 0 4 1
A setConcrete() 0 6 1
A addArgument() 0 5 1
A addArguments() 0 8 2
A addMethodCall() 0 9 1
A addMethodCalls() 0 8 2
A resolve() 0 8 3
A resolveCallable() 0 5 1
A resolveClass() 0 6 1
A invokeMethods() 0 10 2
B resolveNew() 0 40 11
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Container\Definition;
6
7
use League\Container\Argument\{
8
    ArgumentResolverInterface,
9
    ArgumentResolverTrait,
10
    ArgumentInterface,
11
    LiteralArgumentInterface
12
};
13
use League\Container\ContainerAwareTrait;
14
use League\Container\Exception\ContainerException;
15
use Psr\Container\ContainerInterface;
16
use ReflectionClass;
17
18
class Definition implements ArgumentResolverInterface, DefinitionInterface
19
{
20
    use ArgumentResolverTrait;
21
    use ContainerAwareTrait;
22
23
    /**
24
     * @var string
25
     */
26
    protected $alias;
27
28
    /**
29
     * @var mixed
30
     */
31
    protected $concrete;
32
33
    /**
34
     * @var boolean
35
     */
36
    protected $shared = false;
37
38
    /**
39
     * @var array
40
     */
41
    protected $tags = [];
42
43
    /**
44
     * @var array
45
     */
46
    protected $arguments = [];
47
48
    /**
49
     * @var array
50
     */
51
    protected $methods = [];
52
53
    /**
54
     * @var mixed
55
     */
56
    protected $resolved;
57
58
    /**
59
     * @param string     $id
60
     * @param mixed|null $concrete
61
     */
62 72
    public function __construct(string $id, $concrete = null)
63
    {
64 72
        $concrete = $concrete ?? $id;
65 72
        $this->alias    = $id;
66 72
        $this->concrete = $concrete;
67 72
    }
68
69 9
    public function addTag(string $tag): DefinitionInterface
70
    {
71 9
        $this->tags[$tag] = true;
72 9
        return $this;
73
    }
74
75 9
    public function hasTag(string $tag): bool
76
    {
77 9
        return isset($this->tags[$tag]);
78
    }
79
80 39
    public function setAlias(string $id): DefinitionInterface
81
    {
82 39
        $this->alias = $id;
83 39
        return $this;
84
    }
85
86 36
    public function getAlias(): string
87
    {
88 36
        return $this->alias;
89
    }
90
91 9
    public function setShared(bool $shared = true): DefinitionInterface
92
    {
93 9
        $this->shared = $shared;
94 9
        return $this;
95
    }
96
97 9
    public function isShared(): bool
98
    {
99 9
        return $this->shared;
100
    }
101
102 12
    public function getConcrete()
103
    {
104 12
        return $this->concrete;
105
    }
106
107 3
    public function setConcrete($concrete): DefinitionInterface
108
    {
109 3
        $this->concrete = $concrete;
110 3
        $this->resolved = null;
111 3
        return $this;
112
    }
113
114 12
    public function addArgument($arg): DefinitionInterface
115
    {
116 12
        $this->arguments[] = $arg;
117 12
        return $this;
118
    }
119
120 3
    public function addArguments(array $args): DefinitionInterface
121
    {
122 3
        foreach ($args as $arg) {
123 3
            $this->addArgument($arg);
124
        }
125
126 3
        return $this;
127
    }
128
129 3
    public function addMethodCall(string $method, array $args = []): DefinitionInterface
130
    {
131 3
        $this->methods[] = [
132 3
            'method'    => $method,
133 3
            'arguments' => $args
134
        ];
135
136 3
        return $this;
137
    }
138
139 3
    public function addMethodCalls(array $methods = []): DefinitionInterface
140
    {
141 3
        foreach ($methods as $method => $args) {
142 3
            $this->addMethodCall($method, $args);
143
        }
144
145 3
        return $this;
146
    }
147
148 48
    public function resolve()
149
    {
150 48
        if (null !== $this->resolved && $this->isShared()) {
151 9
            return $this->resolved;
152
        }
153
154 48
        return $this->resolveNew();
155
    }
156
157 48
    public function resolveNew()
158
    {
159 48
        $concrete = $this->concrete;
160
161 48
        if (is_callable($concrete)) {
162 12
            $concrete = $this->resolveCallable($concrete);
163
        }
164
165 48
        if ($concrete instanceof LiteralArgumentInterface) {
166 3
            $this->resolved = $concrete->getValue();
167 3
            return $concrete->getValue();
168
        }
169
170 45
        if ($concrete instanceof ArgumentInterface) {
171 3
            $concrete = $concrete->getValue();
172
        }
173
174 45
        if (is_string($concrete) && class_exists($concrete)) {
175 36
            $concrete = $this->resolveClass($concrete);
176
        }
177
178 45
        if (is_object($concrete)) {
179 42
            $concrete = $this->invokeMethods($concrete);
180
        }
181
182
        try {
183 45
            $container = $this->getContainer();
184 15
        } catch (ContainerException $e) {
185 15
            $container = null;
186
        }
187
188
        // if we still have a string, try to pull it from the container
189
        // this allows for `alias -> alias -> ... -> concrete
190 45
        if (is_string($concrete) && $container instanceof ContainerInterface && $container->has($concrete)) {
191 3
            $concrete = $container->get($concrete);
192
        }
193
194 45
        $this->resolved = $concrete;
195 45
        return $concrete;
196
    }
197
198
    /**
199
     * @param callable $concrete
200
     * @return mixed
201
     */
202 12
    protected function resolveCallable(callable $concrete)
203
    {
204 12
        $resolved = $this->resolveArguments($this->arguments);
205 12
        return call_user_func_array($concrete, $resolved);
206
    }
207
208 36
    protected function resolveClass(string $concrete): object
209
    {
210 36
        $resolved   = $this->resolveArguments($this->arguments);
211 36
        $reflection = new ReflectionClass($concrete);
212 36
        return $reflection->newInstanceArgs($resolved);
213
    }
214
215 42
    protected function invokeMethods(object $instance): object
216
    {
217 42
        foreach ($this->methods as $method) {
218 3
            $args = $this->resolveArguments($method['arguments']);
219 3
            $callable = [$instance, $method['method']];
220 3
            call_user_func_array($callable, $args);
221
        }
222
223 42
        return $instance;
224
    }
225
}
226