vendor/contao/core-bundle/src/Routing/ResponseContext/ResponseContext.php line 88

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\Routing\ResponseContext;
  11. use Contao\CoreBundle\Event\AbstractResponseContextEvent;
  12. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  13. final class ResponseContext
  14. {
  15.     public const REQUEST_ATTRIBUTE_NAME '_contao_response_context';
  16.     private array $services = [];
  17.     private array $current = [];
  18.     private ?PartialResponseHeaderBag $headerBag null;
  19.     public function dispatchEvent(AbstractResponseContextEvent $event): void
  20.     {
  21.         if (!$this->has(EventDispatcherInterface::class)) {
  22.             return;
  23.         }
  24.         $event->setResponseContext($this);
  25.         /** @var EventDispatcherInterface $eventDispatcher */
  26.         $eventDispatcher $this->get(EventDispatcherInterface::class);
  27.         $eventDispatcher->dispatch($event);
  28.     }
  29.     public function add(object $service): self
  30.     {
  31.         $this->registerService(\get_class($service), $service);
  32.         return $this;
  33.     }
  34.     public function addLazy(string $classname, \Closure $factory null): self
  35.     {
  36.         $factory ??= fn () => new $classname($this);
  37.         $this->registerService($classname$factory);
  38.         return $this;
  39.     }
  40.     public function has(string $serviceId): bool
  41.     {
  42.         return isset($this->current[$serviceId]);
  43.     }
  44.     public function isInitialized(string $serviceId): bool
  45.     {
  46.         if (!$this->has($serviceId)) {
  47.             return false;
  48.         }
  49.         return !$this->services[$serviceId] instanceof \Closure;
  50.     }
  51.     /**
  52.      * @template T
  53.      *
  54.      * @param class-string<T> $serviceId
  55.      *
  56.      * @return object
  57.      *
  58.      * @phpstan-return T
  59.      */
  60.     public function get(string $serviceId)
  61.     {
  62.         if (!$this->has($serviceId)) {
  63.             throw new \InvalidArgumentException(sprintf('Service "%s" does not exist.'$serviceId));
  64.         }
  65.         $serviceId $this->current[$serviceId];
  66.         // Lazy load the ones with factories
  67.         if (!$this->isInitialized($serviceId)) {
  68.             $service $this->services[$serviceId]();
  69.             $this->services[$serviceId] = $service;
  70.         }
  71.         return $this->services[$serviceId];
  72.     }
  73.     public function getHeaderBag(): PartialResponseHeaderBag
  74.     {
  75.         return $this->headerBag ??= new PartialResponseHeaderBag();
  76.     }
  77.     /**
  78.      * @param \Closure|object $objectOrFactory
  79.      */
  80.     private function registerService(string $serviceId$objectOrFactory): void
  81.     {
  82.         $this->services[$serviceId] = $objectOrFactory;
  83.         $this->current[$serviceId] = $serviceId;
  84.         foreach ($this->getAliases($serviceId) as $alias) {
  85.             $this->current[$alias] = $serviceId;
  86.         }
  87.     }
  88.     private function getAliases(string $classname): array
  89.     {
  90.         $aliases = [];
  91.         $ref = new \ReflectionClass($classname);
  92.         // Automatically add aliases for all interfaces and parents (last one added automatically wins by overriding here)
  93.         foreach ($ref->getInterfaceNames() as $interfaceName) {
  94.             $aliases[] = $interfaceName;
  95.         }
  96.         while ($ref $ref->getParentClass()) {
  97.             $aliases[] = $ref->getName();
  98.         }
  99.         return $aliases;
  100.     }
  101. }