Completed
Pull Request — master (#169)
by Saif Eddin
02:06
created

Container::delegate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php declare(strict_types=1);
2
3
namespace League\Container;
4
5
use League\Container\Definition\{DefinitionAggregate, DefinitionInterface, DefinitionAggregateInterface};
6
use League\Container\Exception\{NotFoundException, ContainerException};
7
use League\Container\Inflector\{InflectorAggregate, InflectorInterface, InflectorAggregateInterface};
8
use League\Container\ServiceProvider\{ServiceProviderAggregate, ServiceProviderAggregateInterface};
9
use Psr\Container\ContainerInterface;
10
11
class Container implements ContainerInterface
12
{
13
    /**
14
     * @var boolean
15
     */
16
    protected $defaultToShared = false;
17
18
    /**
19
     * @var \League\Container\Definition\DefinitionAggregateInterface
20
     */
21
    protected $definitions;
22
23
    /**
24
     * @var \League\Container\ServiceProvider\ServiceProviderAggregateInterface
25
     */
26
    protected $providers;
27
28
    /**
29
     * @var \League\Container\Inflector\InflectorAggregateInterface
30
     */
31
    protected $inflectors;
32
33
    /**
34
     * @var \Psr\Container\ContainerInterface[]
35
     */
36
    protected $delegates = [];
37
38
    /**
39
     * Construct.
40
     *
41
     * @param \League\Container\Definition\DefinitionAggregateInterface|null           $definitions
42
     * @param \League\Container\ServiceProvider\ServiceProviderAggregateInterface|null $providers
43
     * @param \League\Container\Inflector\InflectorAggregateInterface|null             $inflectors
44
     */
45 48
    public function __construct(
46
        DefinitionAggregateInterface      $definitions = null,
47
        ServiceProviderAggregateInterface $providers = null,
48
        InflectorAggregateInterface       $inflectors = null
49
    ) {
50 48
        $this->definitions = $definitions ?? (new DefinitionAggregate);
51 48
        $this->providers   = $providers   ?? (new ServiceProviderAggregate);
52 48
        $this->inflectors  = $inflectors  ?? (new InflectorAggregate);
53
54 48
        if ($this->definitions instanceof ContainerAwareInterface) {
55 48
            $this->definitions->setContainer($this);
56
        }
57
58 48
        if ($this->providers instanceof ContainerAwareInterface) {
59 48
            $this->providers->setContainer($this);
60
        }
61
62 48
        if ($this->inflectors instanceof ContainerAwareInterface) {
63 48
            $this->inflectors->setContainer($this);
64
        }
65 48
    }
66
67
    /**
68
     * Add an item to the container.
69
     *
70
     * @param string  $id
71
     * @param mixed   $concrete
72
     * @param boolean $shared
73
     *
74
     * @return \League\Container\Definition\DefinitionInterface
75
     */
76 27
    public function add(string $id, $concrete = null, bool $shared = null) : DefinitionInterface
77
    {
78 27
        $concrete = $concrete ?? $id;
79 27
        $shared = $shared ?? $this->defaultToShared;
80
81 27
        return $this->definitions->add($id, $concrete, $shared);
82
    }
83
84
    /**
85
     * Proxy to add with shared as true.
86
     *
87
     * @param string $id
88
     * @param mixed  $concrete
89
     *
90
     * @return \League\Container\Definition\DefinitionInterface
91
     */
92 3
    public function share(string $id, $concrete = null) : DefinitionInterface
93
    {
94 3
        return $this->add($id, $concrete, true);
95
    }
96
97
    /**
98
     * Whether the container should default to defining shared definitions.
99
     *
100
     * @param boolean $shared
101
     *
102
     * @return self
103
     */
104 6
    public function defaultToShared(bool $shared = true) : ContainerInterface
105
    {
106 6
        $this->defaultToShared = $shared;
107
108 6
        return $this;
109
    }
110
111
    /**
112
     * Get a definition to extend.
113
     *
114
     * @param string $id [description]
115
     *
116
     * @return \League\Container\Definition\DefinitionInterface
117
     */
118 9
    public function extend(string $id) : DefinitionInterface
119
    {
120 9
        if ($this->providers->provides($id)) {
121 3
            $this->providers->register($id);
122
        }
123
124 9
        if ($this->definitions->has($id)) {
125 6
            return $this->definitions->getDefinition($id);
126
        }
127
128 3
        throw new NotFoundException(
129 3
            sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $id)
130
        );
131
    }
132
133
    /**
134
     * Add a service provider.
135
     *
136
     * @param \League\Container\ServiceProvider\ServiceProviderInterface|string $provider
137
     *
138
     * @return self
139
     */
140 6
    public function addServiceProvider($provider) : self
141
    {
142 6
        $this->providers->add($provider);
143
144 6
        return $this;
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150 27
    public function get($id, bool $new = false)
151
    {
152 27
        if ($this->definitions->has($id)) {
153 18
            $resolved = $this->definitions->resolve($id, $new);
154 18
            return $this->inflectors->inflect($resolved);
155
        }
156
157 12
        if ($this->definitions->hasTag($id)) {
158 3
            $arrayOf = $this->definitions->resolveTagged($id);
159
160 3
            array_walk($arrayOf, function (&$resolved) {
161 3
                $resolved = $this->inflectors->inflect($resolved);
162 3
            });
163
164 3
            return $arrayOf;
165
        }
166
167 9
        if ($this->providers->provides($id)) {
168 3
            $this->providers->register($id);
169
            
170 3
            if(!$this->definitions->has($id) && !$this->definitions->hasTag($id)) {
171
                throw new ContainerException(sprintf('Service provider lied about providing (%s) service', $id));    
172
            }
173
174 3
            return $this->get($id, $new);
175
        }
176
177 6
        foreach ($this->delegates as $delegate) {
178 3
            if ($delegate->has($id)) {
179 3
                $resolved = $delegate->get($id);
180 3
                return $this->inflectors->inflect($resolved);
181
            }
182
        }
183
184 3
        throw new NotFoundException(sprintf('Alias (%s) is not being managed by the container or delegates', $id));
185
    }
186
187
    /**
188
     * {@inheritdoc}
189
     */
190 30
    public function has($id) : bool
191
    {
192 30
        if ($this->definitions->has($id)) {
193 18
            return true;
194
        }
195
196 15
        if ($this->definitions->hasTag($id)) {
197 3
            return true;
198
        }
199
200 12
        if ($this->providers->provides($id)) {
201 3
            return true;
202
        }
203
204 9
        foreach ($this->delegates as $delegate) {
205 3
            if ($delegate->has($id)) {
206 3
                return true;
207
            }
208
        }
209
210 6
        return false;
211
    }
212
213
    /**
214
     * Allows for manipulation of specific types on resolution.
215
     *
216
     * @param string        $type
217
     * @param callable|null $callback
218
     *
219
     * @return \League\Container\Inflector\InflectorInterface
220
     */
221 3
    public function inflector(string $type, callable $callback = null) : InflectorInterface
222
    {
223 3
        return $this->inflectors->add($type, $callback);
224
    }
225
226
    /**
227
     * Delegate a backup container to be checked for services if it
228
     * cannot be resolved via this container.
229
     *
230
     * @param \Psr\Container\ContainerInterface $container
231
     *
232
     * @return self
233
     */
234 3
    public function delegate(ContainerInterface $container) : self
235
    {
236 3
        $this->delegates[] = $container;
237
238 3
        if ($container instanceof ContainerAwareInterface) {
239 3
            $container->setContainer($this);
240
        }
241
242 3
        return $this;
243
    }
244
}
245