Commit 237ed42d authored by Igor Wiedler's avatar Igor Wiedler Committed by Fabien Potencier

Make dispatcher lazy, do not trigger its creation on middleware definition

The dispatcher has quite a few dependencies due to all of the subscribers
that are added to it. One of these is the logger, several other services
are affected as well though.

The listener shortcut methods like on(), before(), after(), error() all
force creation of the dispatcher and thus all of its dependencies. This
makes it impossible to have lazy configuration of those services.

The specific issue that triggered this was lazy configuration of the logger,
which simply does not work once you have before() or after().

By using extend(), all of those shortcut calls can delay the creation of
the dispatcher and thus solve the issue. It will add a slight overhead, but
it should be relatively small, since the results of creating a service are
memoized through share().
parent e9e1b209
...@@ -258,7 +258,11 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte ...@@ -258,7 +258,11 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte
*/ */
public function on($eventName, $callback, $priority = 0) public function on($eventName, $callback, $priority = 0)
{ {
$this['dispatcher']->addListener($eventName, $callback, $priority); $this['dispatcher'] = $this->share($this->extend('dispatcher', function ($dispatcher, $app) use ($callback, $priority, $eventName) {
$dispatcher->addListener($eventName, $callback, $priority);
return $dispatcher;
}));
} }
/** /**
...@@ -272,7 +276,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte ...@@ -272,7 +276,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte
*/ */
public function before($callback, $priority = 0) public function before($callback, $priority = 0)
{ {
$this['dispatcher']->addListener(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($callback) { $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($callback) {
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return; return;
} }
...@@ -296,7 +300,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte ...@@ -296,7 +300,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte
*/ */
public function after($callback, $priority = 0) public function after($callback, $priority = 0)
{ {
$this['dispatcher']->addListener(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($callback) { $this->on(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($callback) {
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return; return;
} }
...@@ -316,7 +320,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte ...@@ -316,7 +320,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte
*/ */
public function finish($callback, $priority = 0) public function finish($callback, $priority = 0)
{ {
$this['dispatcher']->addListener(KernelEvents::TERMINATE, function (PostResponseEvent $event) use ($callback) { $this->on(KernelEvents::TERMINATE, function (PostResponseEvent $event) use ($callback) {
call_user_func($callback, $event->getRequest(), $event->getResponse()); call_user_func($callback, $event->getRequest(), $event->getResponse());
}, $priority); }, $priority);
} }
...@@ -352,7 +356,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte ...@@ -352,7 +356,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte
*/ */
public function error($callback, $priority = -8) public function error($callback, $priority = -8)
{ {
$this['dispatcher']->addListener(KernelEvents::EXCEPTION, new ExceptionListenerWrapper($this, $callback), $priority); $this->on(KernelEvents::EXCEPTION, new ExceptionListenerWrapper($this, $callback), $priority);
} }
/** /**
......
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Silex\Tests;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
class LazyDispatcherTest extends \PHPUnit_Framework_TestCase
{
/** @test */
public function beforeMiddlewareShouldNotCreateDispatcherEarly()
{
$dispatcherCreated = false;
$app = new Application();
$app['dispatcher'] = $app->share($app->extend('dispatcher', function ($dispatcher, $app) use (&$dispatcherCreated) {
$dispatcherCreated = true;
return $dispatcher;
}));
$app->before(function () {});
$this->assertFalse($dispatcherCreated);
$request = Request::create('/');
$app->handle($request);
$this->assertTrue($dispatcherCreated);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment