Completed
Push — 4.x ( 002a94...132f61 )
by Phil
01:28
created

Definition::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
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 66
    public function __construct(string $id, $concrete = null)
63
    {
64 66
        $concrete = $concrete ?? $id;
65 66
        $this->alias    = $id;
66 66
        $this->concrete = $concrete;
67 66
    }
68
69 6
    public function addTag(string $tag): DefinitionInterface
70
    {
71 6
        $this->tags[$tag] = true;
72 6
        return $this;
73
    }
74
75 6
    public function hasTag(string $tag): bool
76
    {
77 6
        return isset($this->tags[$tag]);
78
    }
79
80 36
    public function setAlias(string $id): DefinitionInterface
81
    {
82 36
        $this->alias = $id;
83 36
        return $this;
84
    }
85
86 33
    public function getAlias(): string
87
    {
88 33
        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 42
    public function resolve()
149
    {
150 42
        if (null !== $this->resolved && $this->isShared()) {
151 9
            return $this->resolved;
152
        }
153
154 42
        return $this->resolveNew();
155
    }
156
157 42
    public function resolveNew()
158
    {
159 42
        $concrete = $this->concrete;
160
161 42
        if (is_callable($concrete)) {
162 12
            $concrete = $this->resolveCallable($concrete);
163
        }
164
165 42
        if ($concrete instanceof LiteralArgumentInterface) {
166 3
            $this->resolved = $concrete->getValue();
167 3
            return $concrete->getValue();
168
        }
169
170 39
        if ($concrete instanceof ArgumentInterface) {
171
            $concrete = $concrete->getValue();
172
        }
173
174 39
        if (is_string($concrete) && class_exists($concrete)) {
175 30
            $concrete = $this->resolveClass($concrete);
176
        }
177
178 39
        if (is_object($concrete)) {
179 36
            $concrete = $this->invokeMethods($concrete);
180
        }
181
182
        try {
183 39
            $container = $this->getContainer();
184 12
        } catch (ContainerException $e) {
185 12
            $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 39
        if (is_string($concrete) && $container instanceof ContainerInterface && $container->has($concrete)) {
0 ignored issues
show
Bug introduced by
The class Psr\Container\ContainerInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
191
            $concrete = $container->get($concrete);
192
        }
193
194 39
        $this->resolved = $concrete;
195 39
        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 30
    protected function resolveClass(string $concrete): object
209
    {
210 30
        $resolved   = $this->resolveArguments($this->arguments);
211 30
        $reflection = new ReflectionClass($concrete);
212 30
        return $reflection->newInstanceArgs($resolved);
213
    }
214
215 36
    protected function invokeMethods(object $instance): object
216
    {
217 36
        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 36
        return $instance;
224
    }
225
}
226