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 = [];
  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, [], $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 = [];
  82.         $msg[] = sprintf('Service "%s" not found:'$id);
  83.         if (!$this->container) {
  84.             $class null;
  85.         } elseif ($this->container->has($id) || isset($this->container->getRemovedIds()[$id])) {
  86.             $msg[] = 'even though it exists in the app\'s container,';
  87.         } else {
  88.             try {
  89.                 $this->container->get($id);
  90.                 $class null;
  91.             } catch (ServiceNotFoundException $e) {
  92.                 if ($e->getAlternatives()) {
  93.                     $msg[] = sprintf('did you mean %s? Anyway,'$this->formatAlternatives($e->getAlternatives(), 'or'));
  94.                 } else {
  95.                     $class null;
  96.                 }
  97.             }
  98.         }
  99.         if ($externalId) {
  100.             $msg[] = sprintf('the container inside "%s" is a smaller service locator that %s'$externalId$this->formatAlternatives());
  101.         } else {
  102.             $msg[] = sprintf('the current service locator %s'$this->formatAlternatives());
  103.         }
  104.         if (!$class) {
  105.             // no-op
  106.         } elseif (is_subclass_of($classServiceSubscriberInterface::class)) {
  107.             $msg[] = sprintf('Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "%s::getSubscribedServices()".'preg_replace('/([^\\\\]++\\\\)++/'''$class));
  108.         } else {
  109.             $msg[] = 'Try using dependency injection instead.';
  110.         }
  111.         return implode(' '$msg);
  112.     }
  113.     private function formatAlternatives(array $alternatives null$separator 'and')
  114.     {
  115.         $format '"%s"%s';
  116.         if (null === $alternatives) {
  117.             if (!$alternatives array_keys($this->factories)) {
  118.                 return 'is empty...';
  119.             }
  120.             $format sprintf('only knows about the %s service%s.'$format< \count($alternatives) ? 's' '');
  121.         }
  122.         $last array_pop($alternatives);
  123.         return sprintf($format$alternatives implode('", "'$alternatives) : $last$alternatives sprintf(' %s "%s"'$separator$last) : '');
  124.     }
  125. }