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

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