Passed
Push — 4.x ( e29dbd...b4dbbf )
by Phil
01:44
created

Definition::normaliseAlias()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
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 93
    public function __construct(string $id, $concrete = null)
69
    {
70 93
        $id = static::normaliseAlias($id);
71
72 93
        $concrete = $concrete ?? $id;
73 93
        $this->alias    = $id;
74 93
        $this->concrete = $concrete;
75 62
    }
76
77 9
    public function addTag(string $tag): DefinitionInterface
78
    {
79 9
        $this->tags[$tag] = true;
80 9
        return $this;
81
    }
82
83 15
    public function hasTag(string $tag): bool
84
    {
85 15
        return isset($this->tags[$tag]);
86
    }
87
88 60
    public function setAlias(string $id): DefinitionInterface
89
    {
90 60
        $id = static::normaliseAlias($id);
91
92 60
        $this->alias = $id;
93 60
        return $this;
94
    }
95
96 57
    public function getAlias(): string
97
    {
98 57
        return $this->alias;
99
    }
100
101 9
    public function setShared(bool $shared = true): DefinitionInterface
102
    {
103 9
        $this->shared = $shared;
104 9
        return $this;
105
    }
106
107 9
    public function isShared(): bool
108
    {
109 9
        return $this->shared;
110
    }
111
112 12
    public function getConcrete()
113
    {
114 12
        return $this->concrete;
115
    }
116
117 3
    public function setConcrete($concrete): DefinitionInterface
118
    {
119 3
        $this->concrete = $concrete;
120 3
        $this->resolved = null;
121 3
        return $this;
122
    }
123
124 12
    public function addArgument($arg): DefinitionInterface
125
    {
126 12
        $this->arguments[] = $arg;
127 12
        return $this;
128
    }
129
130 3
    public function addArguments(array $args): DefinitionInterface
131
    {
132 3
        foreach ($args as $arg) {
133 3
            $this->addArgument($arg);
134
        }
135
136 3
        return $this;
137
    }
138
139 3
    public function addMethodCall(string $method, array $args = []): DefinitionInterface
140
    {
141 3
        $this->methods[] = [
142 3
            'method'    => $method,
143 3
            'arguments' => $args
144 1
        ];
145
146 3
        return $this;
147
    }
148
149 3
    public function addMethodCalls(array $methods = []): DefinitionInterface
150
    {
151 3
        foreach ($methods as $method => $args) {
152 3
            $this->addMethodCall($method, $args);
153
        }
154
155 3
        return $this;
156
    }
157
158 57
    public function resolve()
159
    {
160 57
        if (null !== $this->resolved && $this->isShared()) {
161 9
            return $this->resolved;
162
        }
163
164 57
        return $this->resolveNew();
165
    }
166
167 57
    public function resolveNew()
168
    {
169 57
        $concrete = $this->concrete;
170
171 57
        if (is_callable($concrete)) {
172 18
            $concrete = $this->resolveCallable($concrete);
173
        }
174
175 57
        if ($concrete instanceof LiteralArgumentInterface) {
176 3
            $this->resolved = $concrete->getValue();
177 3
            return $concrete->getValue();
178
        }
179
180 54
        if ($concrete instanceof ArgumentInterface) {
181 3
            $concrete = $concrete->getValue();
182
        }
183
184 54
        if (is_string($concrete) && class_exists($concrete)) {
185 36
            $concrete = $this->resolveClass($concrete);
186
        }
187
188 54
        if (is_object($concrete)) {
189 45
            $concrete = $this->invokeMethods($concrete);
190
        }
191
192
        try {
193 54
            $container = $this->getContainer();
194 15
        } catch (ContainerException $e) {
195 15
            $container = null;
196
        }
197
198
        // stop recursive resolving
199 54
        if (is_string($concrete) && in_array($concrete, $this->recursiveCheck)) {
200 3
            $this->resolved = $concrete;
201 3
            return $concrete;
202
        }
203
204
        // if we still have a string, try to pull it from the container
205
        // this allows for `alias -> alias -> ... -> concrete
206 54
        if (is_string($concrete) && $container instanceof ContainerInterface && $container->has($concrete)) {
207 6
            $this->recursiveCheck[] = $concrete;
208 6
            $concrete = $container->get($concrete);
209
        }
210
211 54
        $this->resolved = $concrete;
212 54
        return $concrete;
213
    }
214
215
    /**
216
     * @param callable $concrete
217
     * @return mixed
218
     */
219 18
    protected function resolveCallable(callable $concrete)
220
    {
221 18
        $resolved = $this->resolveArguments($this->arguments);
222 18
        return call_user_func_array($concrete, $resolved);
223
    }
224
225 36
    protected function resolveClass(string $concrete): object
226
    {
227 36
        $resolved   = $this->resolveArguments($this->arguments);
228 36
        $reflection = new ReflectionClass($concrete);
229 36
        return $reflection->newInstanceArgs($resolved);
230
    }
231
232 45
    protected function invokeMethods(object $instance): object
233
    {
234 45
        foreach ($this->methods as $method) {
235 3
            $args = $this->resolveArguments($method['arguments']);
236 3
            $callable = [$instance, $method['method']];
237 3
            call_user_func_array($callable, $args);
238
        }
239
240 45
        return $instance;
241
    }
242
243 114
    public static function normaliseAlias(string $alias): string
244
    {
245 114
        if (strpos($alias, '\\') === 0) {
246 12
            return substr($alias, 1);
247
        }
248
249 114
        return $alias;
250
    }
251
}
252