Completed
Push — master ( 95f414...aebb2f )
by Phil
12:45 queued 05:29
created

Container::has()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 12
c 0
b 0
f 0
ccs 6
cts 6
cp 1
rs 9.2
cc 4
eloc 6
nc 3
nop 1
crap 4
1
<?php
2
3
namespace League\Container;
4
5
use Interop\Container\ContainerInterface as InteropContainerInterface;
6
use League\Container\Argument\RawArgumentInterface;
7
use League\Container\Definition\DefinitionFactory;
8
use League\Container\Definition\DefinitionFactoryInterface;
9
use League\Container\Definition\DefinitionInterface;
10
use League\Container\Exception\NotFoundException;
11
use League\Container\Inflector\InflectorAggregate;
12
use League\Container\Inflector\InflectorAggregateInterface;
13
use League\Container\ServiceProvider\ServiceProviderAggregate;
14
use League\Container\ServiceProvider\ServiceProviderAggregateInterface;
15
16
class Container implements ContainerInterface
17
{
18
    /**
19
     * @var \League\Container\Definition\DefinitionFactoryInterface
20
     */
21
    protected $definitionFactory;
22
23
    /**
24
     * @var \League\Container\Definition\DefinitionInterface[]
25
     */
26
    protected $definitions = [];
27
28
    /**
29
     * @var \League\Container\Definition\DefinitionInterface[]
30
     */
31
    protected $sharedDefinitions = [];
32
33
    /**
34
     * @var \League\Container\Inflector\InflectorAggregateInterface
35
     */
36
    protected $inflectors;
37
38
    /**
39
     * @var \League\Container\ServiceProvider\ServiceProviderAggregateInterface
40
     */
41
    protected $providers;
42
43
    /**
44
     * @var array
45
     */
46
    protected $shared = [];
47
48
    /**
49
     * @var \Interop\Container\ContainerInterface[]
50
     */
51
    protected $delegates = [];
52
53
    /**
54
     * Constructor.
55
     *
56
     * @param \League\Container\ServiceProvider\ServiceProviderAggregateInterface|null $providers
57
     * @param \League\Container\Inflector\InflectorAggregateInterface|null             $inflectors
58
     * @param \League\Container\Definition\DefinitionFactoryInterface|null             $definitionFactory
59
     */
60 57
    public function __construct(
61
        ServiceProviderAggregateInterface $providers         = null,
62
        InflectorAggregateInterface       $inflectors        = null,
63
        DefinitionFactoryInterface        $definitionFactory = null
64
    ) {
65
        // set required dependencies
66 57
        $this->providers         = (is_null($providers))
67 57
                                 ? (new ServiceProviderAggregate)->setContainer($this)
68 57
                                 : $providers->setContainer($this);
69
70 57
        $this->inflectors        = (is_null($inflectors))
71 57
                                 ? (new InflectorAggregate)->setContainer($this)
72 57
                                 : $inflectors->setContainer($this);
73
74 57
        $this->definitionFactory = (is_null($definitionFactory))
75 57
                                 ? (new DefinitionFactory)->setContainer($this)
76 57
                                 : $definitionFactory->setContainer($this);
77 57
    }
78
79
    /**
80
     * {@inheritdoc}
81
     */
82 45
    public function get($alias, array $args = [])
83
    {
84
        try {
85 45
            return $this->getFromThisContainer($alias, $args);
86 21
        } catch (NotFoundException $exception) {
87 21
            if ($this->providers->provides($alias)) {
88 12
                $this->providers->register($alias);
89
90 12
                return $this->getFromThisContainer($alias, $args);
91
            }
92
93 9
            $resolved = $this->getFromDelegate($alias, $args);
94
95 6
            return $this->inflectors->inflect($resolved);
96
        }
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102 21
    public function has($alias)
103
    {
104 21
        if (array_key_exists($alias, $this->definitions) || $this->hasShared($alias)) {
105 15
            return true;
106
        }
107
108 9
        if ($this->providers->provides($alias)) {
109 3
            return true;
110
        }
111
112 9
        return $this->hasInDelegate($alias);
113
    }
114
115
    /**
116
     * Returns a boolean to determine if the container has a shared instance of an alias.
117
     *
118
     * @param  string  $alias
119
     * @param  boolean $resolved
120
     * @return boolean
121
     */
122 51
    public function hasShared($alias, $resolved = false)
123
    {
124 51
        $shared = ($resolved === false) ? array_merge($this->shared, $this->sharedDefinitions) : $this->shared;
125
126 51
        return (array_key_exists($alias, $shared));
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132 45
    public function add($alias, $concrete = null, $share = false)
133
    {
134 45
        unset($this->shared[$alias]);
135 45
        unset($this->definitions[$alias]);
136 45
        unset($this->sharedDefinitions[$alias]);
137
138 45
        if (is_null($concrete)) {
139 3
            $concrete = $alias;
140 3
        }
141
142 45
        $definition = $this->definitionFactory->getDefinition($alias, $concrete);
143
144 45
        if ($definition instanceof DefinitionInterface) {
145 39
            if ($share === false) {
146 18
                $this->definitions[$alias] = $definition;
147 18
            } else {
148 33
                $this->sharedDefinitions[$alias] = $definition;
149
            }
150
151 39
            return $definition;
152
        }
153
154
        // dealing with a value that cannot build a definition
155 6
        $this->shared[$alias] = $concrete;
156 6
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161 33
    public function share($alias, $concrete = null)
162
    {
163 33
        return $this->add($alias, $concrete, true);
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169 12
    public function addServiceProvider($provider)
170
    {
171 12
        $this->providers->add($provider);
172
173 12
        return $this;
174
    }
175
176
    /**
177
     * {@inheritdoc}
178
     */
179 6
    public function extend($alias)
180
    {
181 6
        if ($this->providers->provides($alias)) {
182 3
            $this->providers->register($alias);
183 3
        }
184
185 6
        if (array_key_exists($alias, $this->definitions)) {
186 3
            return $this->definitions[$alias];
187
        }
188
189 6
        if (array_key_exists($alias, $this->sharedDefinitions)) {
190 3
            return $this->sharedDefinitions[$alias];
191
        }
192
193 3
        throw new NotFoundException(
194 3
            sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $alias)
195 3
        );
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    public function inflector($type, callable $callback = null)
202
    {
203
        return $this->inflectors->add($type, $callback);
204
    }
205
206
    /**
207
     * {@inheritdoc}
208
     */
209
    public function call(callable $callable, array $args = [])
210
    {
211
        return (new ReflectionContainer)->setContainer($this)->call($callable, $args);
212
    }
213
214
    /**
215
     * Delegate a backup container to be checked for services if it
216
     * cannot be resolved via this container.
217
     *
218
     * @param  \Interop\Container\ContainerInterface $container
219
     * @return $this
220
     */
221 9
    public function delegate(InteropContainerInterface $container)
222
    {
223 9
        $this->delegates[] = $container;
224
225 9
        if ($container instanceof ImmutableContainerAwareInterface) {
226 3
            $container->setContainer($this);
227 3
        }
228
229 9
        return $this;
230
    }
231
232
    /**
233
     * Returns true if service is registered in one of the delegated backup containers.
234
     *
235
     * @param  string $alias
236
     * @return boolean
237
     */
238 9
    public function hasInDelegate($alias)
239
    {
240 9
        foreach ($this->delegates as $container) {
241 3
            if ($container->has($alias)) {
242 3
                return true;
243
            }
244 9
        }
245
246 6
        return false;
247
    }
248
249
    /**
250
     * Attempt to get a service from the stack of delegated backup containers.
251
     *
252
     * @param  string $alias
253
     * @param  array  $args
254
     * @return mixed
255
     */
256 9
    protected function getFromDelegate($alias, array $args = [])
257
    {
258 9
        foreach ($this->delegates as $container) {
259 6
            if ($container->has($alias)) {
260 6
                return $container->get($alias, $args);
261
            }
262
263 3
            continue;
264 3
        }
265
266 3
        throw new NotFoundException(
267 3
            sprintf('Alias (%s) is not being managed by the container', $alias)
268 3
        );
269
270
    }
271
272
    /**
273
     * Get a service that has been registered in this container.
274
     *
275
     * @param  string $alias
276
     * @param  array $args
277
     * @return mixed
278
     */
279 45
    protected function getFromThisContainer($alias, array $args = [])
280
    {
281 45
        if ($this->hasShared($alias, true)) {
282 18
            $shared = $this->inflectors->inflect($this->shared[$alias]);
283 18
            if ($shared instanceof RawArgumentInterface) {
284 3
                return $shared->getValue();
285
            }
286 15
            return $shared;
287
        }
288
289 39
        if (array_key_exists($alias, $this->sharedDefinitions)) {
290 27
            $shared = $this->inflectors->inflect($this->sharedDefinitions[$alias]->build());
291 27
            $this->shared[$alias] = $shared;
292 27
            return $shared;
293
        }
294
295 30
        if (array_key_exists($alias, $this->definitions)) {
296 12
            return $this->inflectors->inflect(
297 12
                $this->definitions[$alias]->build($args)
298 12
            );
299
        }
300
301 21
        throw new NotFoundException(
302 21
            sprintf('Alias (%s) is not being managed by the container', $alias)
303 21
        );
304
    }
305
}
306