Completed
Pull Request — master (#112)
by Hannes
02:57
created

Container::hasShared()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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