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

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\ContainerExceptionInterface;
  12. use Psr\Container\NotFoundExceptionInterface;
  13. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  14. use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  15. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  16. use Symfony\Contracts\Service\ServiceLocatorTrait;
  17. use Symfony\Contracts\Service\ServiceProviderInterface;
  18. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  19. /**
  20.  * @author Robin Chalas <robin.chalas@gmail.com>
  21.  * @author Nicolas Grekas <p@tchwork.com>
  22.  */
  23. class ServiceLocator implements ServiceProviderInterface
  24. {
  25.     use ServiceLocatorTrait {
  26.         get as private doGet;
  27.     }
  28.     private $externalId;
  29.     private $container;
  30.     /**
  31.      * {@inheritdoc}
  32.      *
  33.      * @return mixed
  34.      */
  35.     public function get(string $id)
  36.     {
  37.         if (!$this->externalId) {
  38.             return $this->doGet($id);
  39.         }
  40.         try {
  41.             return $this->doGet($id);
  42.         } catch (RuntimeException $e) {
  43.             $what sprintf('service "%s" required by "%s"'$id$this->externalId);
  44.             $message preg_replace('/service "\.service_locator\.[^"]++"/'$what$e->getMessage());
  45.             if ($e->getMessage() === $message) {
  46.                 $message sprintf('Cannot resolve %s: %s'$what$message);
  47.             }
  48.             $r = new \ReflectionProperty($e'message');
  49.             $r->setAccessible(true);
  50.             $r->setValue($e$message);
  51.             throw $e;
  52.         }
  53.     }
  54.     public function __invoke(string $id)
  55.     {
  56.         return isset($this->factories[$id]) ? $this->get($id) : null;
  57.     }
  58.     /**
  59.      * @internal
  60.      *
  61.      * @return static
  62.      */
  63.     public function withContext(string $externalIdContainer $container): self
  64.     {
  65.         $locator = clone $this;
  66.         $locator->externalId $externalId;
  67.         $locator->container $container;
  68.         return $locator;
  69.     }
  70.     private function createNotFoundException(string $id): NotFoundExceptionInterface
  71.     {
  72.         if ($this->loading) {
  73.             $msg sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s'end($this->loading), $id$this->formatAlternatives());
  74.             return new ServiceNotFoundException($idend($this->loading) ?: nullnull, [], $msg);
  75.         }
  76.         $class debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT \DEBUG_BACKTRACE_IGNORE_ARGS4);
  77.         $class = isset($class[3]['object']) ? \get_class($class[3]['object']) : null;
  78.         $externalId $this->externalId ?: $class;
  79.         $msg = [];
  80.         $msg[] = sprintf('Service "%s" not found:'$id);
  81.         if (!$this->container) {
  82.             $class null;
  83.         } elseif ($this->container->has($id) || isset($this->container->getRemovedIds()[$id])) {
  84.             $msg[] = 'even though it exists in the app\'s container,';
  85.         } else {
  86.             try {
  87.                 $this->container->get($id);
  88.                 $class null;
  89.             } catch (ServiceNotFoundException $e) {
  90.                 if ($e->getAlternatives()) {
  91.                     $msg[] = sprintf('did you mean %s? Anyway,'$this->formatAlternatives($e->getAlternatives(), 'or'));
  92.                 } else {
  93.                     $class null;
  94.                 }
  95.             }
  96.         }
  97.         if ($externalId) {
  98.             $msg[] = sprintf('the container inside "%s" is a smaller service locator that %s'$externalId$this->formatAlternatives());
  99.         } else {
  100.             $msg[] = sprintf('the current service locator %s'$this->formatAlternatives());
  101.         }
  102.         if (!$class) {
  103.             // no-op
  104.         } elseif (is_subclass_of($classServiceSubscriberInterface::class)) {
  105.             $msg[] = sprintf('Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "%s::getSubscribedServices()".'preg_replace('/([^\\\\]++\\\\)++/'''$class));
  106.         } else {
  107.             $msg[] = 'Try using dependency injection instead.';
  108.         }
  109.         return new ServiceNotFoundException($idend($this->loading) ?: nullnull, [], implode(' '$msg));
  110.     }
  111.     private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface
  112.     {
  113.         return new ServiceCircularReferenceException($id$path);
  114.     }
  115.     private function formatAlternatives(?array $alternatives nullstring $separator 'and'): string
  116.     {
  117.         $format '"%s"%s';
  118.         if (null === $alternatives) {
  119.             if (!$alternatives array_keys($this->factories)) {
  120.                 return 'is empty...';
  121.             }
  122.             $format sprintf('only knows about the %s service%s.'$format\count($alternatives) ? 's' '');
  123.         }
  124.         $last array_pop($alternatives);
  125.         return sprintf($format$alternatives implode('", "'$alternatives) : $last$alternatives sprintf(' %s "%s"'$separator$last) : '');
  126.     }
  127. }