Passed
Push — 4.x ( 7477c3...10716b )
by Phil
13:00
created

Definition::resolveNew()   C

Complexity

Conditions 13
Paths 98

Size

Total Lines 46
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 13

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 24
c 1
b 0
f 0
dl 0
loc 46
ccs 24
cts 24
cp 1
rs 6.6166
cc 13
nc 98
nop 0
crap 13

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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