Completed
Pull Request — master (#126)
by Phil
11:29
created

Definition::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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