vendor/symfony/dependency-injection/ServiceLocator.php line 64

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\DependencyInjection;
  11. use Psr\Container\ContainerInterface as PsrContainerInterface;
  12. use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  13. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  14. /**
  15.  * @author Robin Chalas <robin.chalas@gmail.com>
  16.  * @author Nicolas Grekas <p@tchwork.com>
  17.  */
  18. class ServiceLocator implements PsrContainerInterface
  19. {
  20.     private $factories;
  21.     private $loading = array();
  22.     private $externalId;
  23.     private $container;
  24.     /**
  25.      * @param callable[] $factories
  26.      */
  27.     public function __construct(array $factories)
  28.     {
  29.         $this->factories $factories;
  30.     }
  31.     /**
  32.      * {@inheritdoc}
  33.      */
  34.     public function has($id)
  35.     {
  36.         return isset($this->factories[$id]);
  37.     }
  38.     /**
  39.      * {@inheritdoc}
  40.      */
  41.     public function get($id)
  42.     {
  43.         if (!isset($this->factories[$id])) {
  44.             throw new ServiceNotFoundException($idend($this->loading) ?: nullnull, array(), $this->createServiceNotFoundMessage($id));
  45.         }
  46.         if (isset($this->loading[$id])) {
  47.             $ids array_values($this->loading);
  48.             $ids = \array_slice($this->loadingarray_search($id$ids));
  49.             $ids[] = $id;
  50.             throw new ServiceCircularReferenceException($id$ids);
  51.         }
  52.         $this->loading[$id] = $id;
  53.         try {
  54.             return $this->factories[$id]();
  55.         } finally {
  56.             unset($this->loading[$id]);
  57.         }
  58.     }
  59.     public function __invoke($id)
  60.     {
  61.         return isset($this->factories[$id]) ? $this->get($id) : null;
  62.     }
  63.     /**
  64.      * @internal
  65.      */
  66.     public function withContext($externalIdContainer $container)
  67.     {
  68.         $locator = clone $this;
  69.         $locator->externalId $externalId;
  70.         $locator->container $container;
  71.         return $locator;
  72.     }
  73.     private function createServiceNotFoundMessage($id)
  74.     {
  75.         if ($this->loading) {
  76.             return sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s'end($this->loading), $id$this->formatAlternatives());
  77.         }
  78.         $class debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT DEBUG_BACKTRACE_IGNORE_ARGS3);
  79.         $class = isset($class[2]['object']) ? \get_class($class[2]['object']) : null;
  80.         $externalId $this->externalId ?: $class;
  81.         $msg sprintf('Service "%s" not found: '$id);
  82.         if (!$this->container) {
  83.             $class null;
  84.         } elseif ($this->container->has($id) || isset($this->container->getRemovedIds()[$id])) {
  85.             $msg .= 'even though it exists in the app\'s container, ';
  86.         } else {
  87.             try {
  88.                 $this->container->get($id);
  89.                 $class null;
  90.             } catch (ServiceNotFoundException $e) {
  91.                 if ($e->getAlternatives()) {
  92.                     $msg .= sprintf(' did you mean %s? Anyway, '$this->formatAlternatives($e->getAlternatives(), 'or'));
  93.                 } else {
  94.                     $class null;
  95.                 }
  96.             }
  97.         }
  98.         if ($externalId) {
  99.             $msg .= sprintf('the container inside "%s" is a smaller service locator that %s'$externalId$this->formatAlternatives());
  100.         } else {
  101.             $msg .= sprintf('the current service locator %s'$this->formatAlternatives());
  102.         }
  103.         if (!$class) {
  104.             // no-op
  105.         } elseif (is_subclass_of($classServiceSubscriberInterface::class)) {
  106.             $msg .= sprintf(' Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "%s::getSubscribedServices()".'preg_replace('/([^\\\\]++\\\\)++/'''$class));
  107.         } else {
  108.             $msg .= 'Try using dependency injection instead.';
  109.         }
  110.         return $msg;
  111.     }
  112.     private function formatAlternatives(array $alternatives null$separator 'and')
  113.     {
  114.         $format '"%s"%s';
  115.         if (null === $alternatives) {
  116.             if (!$alternatives array_keys($this->factories)) {
  117.                 return 'is empty...';
  118.             }
  119.             $format sprintf('only knows about the %s service%s.'$format< \count($alternatives) ? 's' '');
  120.         }
  121.         $last array_pop($alternatives);
  122.         return sprintf($format$alternatives implode('", "'$alternatives) : $last$alternatives sprintf(' %s "%s"'$separator$last) : '');
  123.     }
  124. }