<?phpdeclare(strict_types=1);/* * This file is part of Contao. * * (c) Leo Feyer * * @license LGPL-3.0-or-later */namespace Contao\CoreBundle\Routing\ResponseContext;use Contao\CoreBundle\Event\AbstractResponseContextEvent;use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;final class ResponseContext{ public const REQUEST_ATTRIBUTE_NAME = '_contao_response_context'; private array $services = []; private array $current = []; private ?PartialResponseHeaderBag $headerBag = null; public function dispatchEvent(AbstractResponseContextEvent $event): void { if (!$this->has(EventDispatcherInterface::class)) { return; } $event->setResponseContext($this); /** @var EventDispatcherInterface $eventDispatcher */ $eventDispatcher = $this->get(EventDispatcherInterface::class); $eventDispatcher->dispatch($event); } public function add(object $service): self { $this->registerService(\get_class($service), $service); return $this; } public function addLazy(string $classname, \Closure $factory = null): self { $factory ??= fn () => new $classname($this); $this->registerService($classname, $factory); return $this; } public function has(string $serviceId): bool { return isset($this->current[$serviceId]); } public function isInitialized(string $serviceId): bool { if (!$this->has($serviceId)) { return false; } return !$this->services[$serviceId] instanceof \Closure; } /** * @template T * * @param class-string<T> $serviceId * * @return object * * @phpstan-return T */ public function get(string $serviceId) { if (!$this->has($serviceId)) { throw new \InvalidArgumentException(sprintf('Service "%s" does not exist.', $serviceId)); } $serviceId = $this->current[$serviceId]; // Lazy load the ones with factories if (!$this->isInitialized($serviceId)) { $service = $this->services[$serviceId](); $this->services[$serviceId] = $service; } return $this->services[$serviceId]; } public function getHeaderBag(): PartialResponseHeaderBag { return $this->headerBag ??= new PartialResponseHeaderBag(); } /** * @param \Closure|object $objectOrFactory */ private function registerService(string $serviceId, $objectOrFactory): void { $this->services[$serviceId] = $objectOrFactory; $this->current[$serviceId] = $serviceId; foreach ($this->getAliases($serviceId) as $alias) { $this->current[$alias] = $serviceId; } } private function getAliases(string $classname): array { $aliases = []; $ref = new \ReflectionClass($classname); // Automatically add aliases for all interfaces and parents (last one added automatically wins by overriding here) foreach ($ref->getInterfaceNames() as $interfaceName) { $aliases[] = $interfaceName; } while ($ref = $ref->getParentClass()) { $aliases[] = $ref->getName(); } return $aliases; }}