3 namespace League\Container;
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;
16 class Container implements ContainerInterface
19 * @var \League\Container\Definition\DefinitionFactoryInterface
21 protected $definitionFactory;
24 * @var \League\Container\Definition\DefinitionInterface[]
26 protected $definitions = [];
29 * @var \League\Container\Definition\DefinitionInterface[]
31 protected $sharedDefinitions = [];
34 * @var \League\Container\Inflector\InflectorAggregateInterface
36 protected $inflectors;
39 * @var \League\Container\ServiceProvider\ServiceProviderAggregateInterface
46 protected $shared = [];
49 * @var \Interop\Container\ContainerInterface[]
51 protected $delegates = [];
56 * @param \League\Container\ServiceProvider\ServiceProviderAggregateInterface|null $providers
57 * @param \League\Container\Inflector\InflectorAggregateInterface|null $inflectors
58 * @param \League\Container\Definition\DefinitionFactoryInterface|null $definitionFactory
60 public function __construct(
61 ServiceProviderAggregateInterface $providers = null,
62 InflectorAggregateInterface $inflectors = null,
63 DefinitionFactoryInterface $definitionFactory = null
65 // set required dependencies
66 $this->providers = (is_null($providers))
67 ? (new ServiceProviderAggregate)->setContainer($this)
68 : $providers->setContainer($this);
70 $this->inflectors = (is_null($inflectors))
71 ? (new InflectorAggregate)->setContainer($this)
72 : $inflectors->setContainer($this);
74 $this->definitionFactory = (is_null($definitionFactory))
75 ? (new DefinitionFactory)->setContainer($this)
76 : $definitionFactory->setContainer($this);
82 public function get($alias, array $args = [])
85 return $this->getFromThisContainer($alias, $args);
86 } catch (NotFoundException $exception) {
87 if ($this->providers->provides($alias)) {
88 $this->providers->register($alias);
90 return $this->getFromThisContainer($alias, $args);
93 $resolved = $this->getFromDelegate($alias, $args);
95 return $this->inflectors->inflect($resolved);
102 public function has($alias)
104 if (array_key_exists($alias, $this->definitions) || $this->hasShared($alias)) {
108 if ($this->providers->provides($alias)) {
112 return $this->hasInDelegate($alias);
116 * Returns a boolean to determine if the container has a shared instance of an alias.
118 * @param string $alias
119 * @param boolean $resolved
122 public function hasShared($alias, $resolved = false)
124 $shared = ($resolved === false) ? array_merge($this->shared, $this->sharedDefinitions) : $this->shared;
126 return (array_key_exists($alias, $shared));
132 public function add($alias, $concrete = null, $share = false)
134 unset($this->shared[$alias]);
135 unset($this->definitions[$alias]);
136 unset($this->sharedDefinitions[$alias]);
138 if (is_null($concrete)) {
142 $definition = $this->definitionFactory->getDefinition($alias, $concrete);
144 if ($definition instanceof DefinitionInterface) {
145 if ($share === false) {
146 $this->definitions[$alias] = $definition;
148 $this->sharedDefinitions[$alias] = $definition;
154 // dealing with a value that cannot build a definition
155 $this->shared[$alias] = $concrete;
161 public function share($alias, $concrete = null)
163 return $this->add($alias, $concrete, true);
169 public function addServiceProvider($provider)
171 $this->providers->add($provider);
179 public function extend($alias)
181 if ($this->providers->provides($alias)) {
182 $this->providers->register($alias);
185 if (array_key_exists($alias, $this->definitions)) {
186 return $this->definitions[$alias];
189 if (array_key_exists($alias, $this->sharedDefinitions)) {
190 return $this->sharedDefinitions[$alias];
193 throw new NotFoundException(
194 sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $alias)
201 public function inflector($type, callable $callback = null)
203 return $this->inflectors->add($type, $callback);
209 public function call(callable $callable, array $args = [])
211 return (new ReflectionContainer)->setContainer($this)->call($callable, $args);
215 * Delegate a backup container to be checked for services if it
216 * cannot be resolved via this container.
218 * @param \Interop\Container\ContainerInterface $container
221 public function delegate(InteropContainerInterface $container)
223 $this->delegates[] = $container;
225 if ($container instanceof ImmutableContainerAwareInterface) {
226 $container->setContainer($this);
233 * Returns true if service is registered in one of the delegated backup containers.
235 * @param string $alias
238 public function hasInDelegate($alias)
240 foreach ($this->delegates as $container) {
241 if ($container->has($alias)) {
250 * Attempt to get a service from the stack of delegated backup containers.
252 * @param string $alias
256 protected function getFromDelegate($alias, array $args = [])
258 foreach ($this->delegates as $container) {
259 if ($container->has($alias)) {
260 return $container->get($alias, $args);
266 throw new NotFoundException(
267 sprintf('Alias (%s) is not being managed by the container', $alias)
273 * Get a service that has been registered in this container.
275 * @param string $alias
279 protected function getFromThisContainer($alias, array $args = [])
281 if ($this->hasShared($alias, true)) {
282 $shared = $this->inflectors->inflect($this->shared[$alias]);
283 if ($shared instanceof RawArgumentInterface) {
284 return $shared->getValue();
289 if (array_key_exists($alias, $this->sharedDefinitions)) {
290 $shared = $this->inflectors->inflect($this->sharedDefinitions[$alias]->build());
291 $this->shared[$alias] = $shared;
295 if (array_key_exists($alias, $this->definitions)) {
296 return $this->inflectors->inflect(
297 $this->definitions[$alias]->build($args)
301 throw new NotFoundException(
302 sprintf('Alias (%s) is not being managed by the container', $alias)