Completed
Push — master ( 1fff31...95f414 )
by Phil
07:42
created

Container::share()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 2
crap 1
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
        try {
84 42
            return $this->getFromThisContainer($alias, $args);
85 21
        } catch (NotFoundException $exception) {
86 21
            if ($this->providers->provides($alias)) {
87 12
                $this->providers->register($alias);
88
89 12
                return $this->getFromThisContainer($alias, $args);
90
            }
91
92 9
            $resolved = $this->getFromDelegate($alias, $args);
93
94 6
            return $this->inflectors->inflect($resolved);
95
        }
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101 18
    public function has($alias)
102
    {
103 18
        if (array_key_exists($alias, $this->definitions) || $this->hasShared($alias)) {
104 12
            return true;
105
        }
106
107 9
        if ($this->providers->provides($alias)) {
108 3
            return true;
109
        }
110
111 9
        return $this->hasInDelegate($alias);
112
    }
113
114
    /**
115
     * Returns a boolean to determine if the container has a shared instance of an alias.
116
     *
117
     * @param  string  $alias
118
     * @param  boolean $resolved
119
     * @return boolean
120
     */
121 48
    public function hasShared($alias, $resolved = false)
122
    {
123 48
        $shared = ($resolved === false) ? array_merge($this->shared, $this->sharedDefinitions) : $this->shared;
124
125 48
        return (array_key_exists($alias, $shared));
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 42
    public function add($alias, $concrete = null, $share = false)
132
    {
133 42
        unset($this->shared[$alias]);
134 42
        unset($this->definitions[$alias]);
135 42
        unset($this->sharedDefinitions[$alias]);
136
137 42
        if (is_null($concrete)) {
138 3
            $concrete = $alias;
139 3
        }
140
141 42
        $definition = $this->definitionFactory->getDefinition($alias, $concrete);
142
143 42
        if ($definition instanceof DefinitionInterface) {
144 39
            if ($share === false) {
145 18
                $this->definitions[$alias] = $definition;
146 18
            } else {
147 33
                $this->sharedDefinitions[$alias] = $definition;
148
            }
149
150 39
            return $definition;
151
        }
152
153
        // dealing with a value that cannot build a definition
154 3
        $this->shared[$alias] = $concrete;
155 3
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160 33
    public function share($alias, $concrete = null)
161
    {
162 33
        return $this->add($alias, $concrete, true);
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168 12
    public function addServiceProvider($provider)
169
    {
170 12
        $this->providers->add($provider);
171
172 12
        return $this;
173
    }
174
175
    /**
176
     * {@inheritdoc}
177
     */
178 6
    public function extend($alias)
179
    {
180 6
        if ($this->providers->provides($alias)) {
181 3
            $this->providers->register($alias);
182 3
        }
183
184 6
        if (array_key_exists($alias, $this->definitions)) {
185 3
            return $this->definitions[$alias];
186
        }
187
188 6
        if (array_key_exists($alias, $this->sharedDefinitions)) {
189 3
            return $this->sharedDefinitions[$alias];
190
        }
191
192 3
        throw new NotFoundException(
193 3
            sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $alias)
194 3
        );
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200
    public function inflector($type, callable $callback = null)
201
    {
202
        return $this->inflectors->add($type, $callback);
203
    }
204
205
    /**
206
     * {@inheritdoc}
207
     */
208
    public function call(callable $callable, array $args = [])
209
    {
210
        return (new ReflectionContainer)->setContainer($this)->call($callable, $args);
211
    }
212
213
    /**
214
     * Delegate a backup container to be checked for services if it
215
     * cannot be resolved via this container.
216
     *
217
     * @param  \Interop\Container\ContainerInterface $container
218
     * @return $this
219
     */
220 9
    public function delegate(InteropContainerInterface $container)
221
    {
222 9
        $this->delegates[] = $container;
223
224 9
        if ($container instanceof ImmutableContainerAwareInterface) {
225 3
            $container->setContainer($this);
226 3
        }
227
228 9
        return $this;
229
    }
230
231
    /**
232
     * Returns true if service is registered in one of the delegated backup containers.
233
     *
234
     * @param  string $alias
235
     * @return boolean
236
     */
237 9
    public function hasInDelegate($alias)
238
    {
239 9
        foreach ($this->delegates as $container) {
240 3
            if ($container->has($alias)) {
241 3
                return true;
242
            }
243 9
        }
244
245 6
        return false;
246
    }
247
248
    /**
249
     * Attempt to get a service from the stack of delegated backup containers.
250
     *
251
     * @param  string $alias
252
     * @param  array  $args
253
     * @return mixed
254
     */
255 9
    protected function getFromDelegate($alias, array $args = [])
256
    {
257 9
        foreach ($this->delegates as $container) {
258 6
            if ($container->has($alias)) {
259 6
                return $container->get($alias, $args);
260
            }
261
262 3
            continue;
263 3
        }
264
265 3
        throw new NotFoundException(
266 3
            sprintf('Alias (%s) is not being managed by the container', $alias)
267 3
        );
268
269
    }
270
271
    /**
272
     * Get a service that has been registered in this container.
273
     *
274
     * @param  string $alias
275
     * @param  array $args
276
     * @return mixed
277
     */
278 42
    protected function getFromThisContainer($alias, array $args = [])
279
    {
280 42
        if ($this->hasShared($alias, true)) {
281 15
            return $this->inflectors->inflect($this->shared[$alias]);
282
        }
283
284 39
        if (array_key_exists($alias, $this->sharedDefinitions)) {
285 27
            $shared = $this->inflectors->inflect($this->sharedDefinitions[$alias]->build());
286 27
            $this->shared[$alias] = $shared;
287 27
            return $shared;
288
        }
289
290 30
        if (array_key_exists($alias, $this->definitions)) {
291 12
            return $this->inflectors->inflect(
292 12
                $this->definitions[$alias]->build($args)
293 12
            );
294
        }
295
296 21
        throw new NotFoundException(
297 21
            sprintf('Alias (%s) is not being managed by the container', $alias)
298 21
        );
299
    }
300
}
301