Skip to content

Commit

Permalink
Added support for lazy services
Browse files Browse the repository at this point in the history
  • Loading branch information
Toflar committed Jun 11, 2021
1 parent fbe8206 commit 41b1c60
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function createResponseContext(): ResponseContext
public function createWebpageResponseContext(): ResponseContext
{
$context = $this->createResponseContext();
$context->add(new HtmlHeadBag());
$context->addLazy(HtmlHeadBag::class, static function () { return new HtmlHeadBag(); });

return $context;
}
Expand All @@ -49,10 +49,6 @@ public function createContaoWebpageResponseContext(PageModel $pageModel): Respon
{
$context = $this->createWebpageResponseContext();

if (!$context->has(HtmlHeadBag::class)) {
return $context;
}

/** @var HtmlHeadBag $htmlHeadBag */
$htmlHeadBag = $context->get(HtmlHeadBag::class);

Expand Down
22 changes: 15 additions & 7 deletions core-bundle/src/Routing/ResponseContext/ResponseContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@

namespace Contao\CoreBundle\Routing\ResponseContext;

use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;

final class ResponseContext
{
public const REQUEST_ATTRIBUTE_NAME = '_contao_response_context';

/**
* @var array
* @var array<string,\Closure>
*/
private $services;

Expand All @@ -32,17 +30,22 @@ final class ResponseContext

public function add(object $service): self
{
$this->services[\get_class($service)] = $service;
return $this->addLazy(\get_class($service), static function () use ($service) { return $service; });
}

public function addLazy(string $classname, \Closure $factory)
{
$this->services[$classname] = $factory;

$ref = new \ReflectionClass($service);
$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) {
$this->services[$interfaceName] = $service;
$this->services[$interfaceName] = $factory;
}

while ($ref = $ref->getParentClass()) {
$this->services[$ref->getName()] = $service;
$this->services[$ref->getName()] = $factory;
}

return $this;
Expand All @@ -68,6 +71,11 @@ public function get(string $serviceId)
throw new \InvalidArgumentException(sprintf('Service "%s" does not exist.', $serviceId));
}

// Lazy load the ones with factories
if ($this->services[$serviceId] instanceof \Closure) {
$this->services[$serviceId] = $this->services[$serviceId]();
}

return $this->services[$serviceId];
}

Expand Down
12 changes: 12 additions & 0 deletions core-bundle/tests/Routing/ResponseContext/ResponseContextTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ public function testCanAddAndGetServices(): void
$this->assertInstanceOf(HtmlHeadBag::class, $context->get(HtmlHeadBag::class));
}

public function testLazyServices(): void
{
$context = new ResponseContext();

$this->assertFalse($context->has(HtmlHeadBag::class));

$context->addLazy(HtmlHeadBag::class, static function () { return new HtmlHeadBag(); });

$this->assertTrue($context->has(HtmlHeadBag::class));
$this->assertInstanceOf(HtmlHeadBag::class, $context->get(HtmlHeadBag::class));
}

public function testGettingANonExistentServiceThrows(): void
{
$this->expectException(\InvalidArgumentException::class);
Expand Down

0 comments on commit 41b1c60

Please sign in to comment.