Browse Source

made all event listeners lazy loaded

 * The register() method on all listeners has been removed
 * Instead, the information is now put directly in the DIC tag

For instance, a listener on core.request had this method:

   public function register(EventDispatcher $dispatcher, $priority = 0)
   {
       $dispatcher->connect('core.response', array($this, 'filter'), $priority);
   }

And this tag in the DIC configuration:

  <tag name="kernel.listener" />

Now, it only has the following configuration:

  <tag name="kernel.listener" event="core.response" method="filter" priority="0" />

The event and method attributes are now mandatory.
Fabien Potencier 14 năm trước cách đây
mục cha
commit
1c11d81611
23 tập tin đã thay đổi với 106 bổ sung142 xóa
  1. 2 9
      src/Symfony/Bundle/FrameworkBundle/Controller/ParamConverterListener.php
  2. 6 2
      src/Symfony/Bundle/FrameworkBundle/Debug/EventDispatcher.php
  3. 19 8
      src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/RegisterKernelListenersPass.php
  4. 35 4
      src/Symfony/Bundle/FrameworkBundle/EventDispatcher.php
  5. 2 11
      src/Symfony/Bundle/FrameworkBundle/RequestListener.php
  6. 1 0
      src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml
  7. 2 2
      src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml
  8. 2 2
      src/Symfony/Bundle/FrameworkBundle/Resources/config/param_converter.xml
  9. 3 2
      src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml
  10. 5 3
      src/Symfony/Bundle/FrameworkBundle/Resources/config/security.xml
  11. 1 0
      src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml
  12. 6 6
      src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml
  13. 2 2
      src/Symfony/Bundle/WebProfilerBundle/Resources/config/toolbar.xml
  14. 2 11
      src/Symfony/Bundle/WebProfilerBundle/WebDebugToolbarListener.php
  15. 3 15
      src/Symfony/Component/HttpKernel/Cache/EsiListener.php
  16. 2 11
      src/Symfony/Component/HttpKernel/Debug/ExceptionListener.php
  17. 3 12
      src/Symfony/Component/HttpKernel/Profiler/ProfilerListener.php
  18. 0 1
      src/Symfony/Component/HttpKernel/Resources/bin/packager.php
  19. 2 11
      src/Symfony/Component/HttpKernel/ResponseListener.php
  20. 4 13
      src/Symfony/Component/HttpKernel/Security/Firewall.php
  21. 0 4
      src/Symfony/Component/HttpKernel/bootstrap.php
  22. 3 12
      tests/Symfony/Tests/Component/HttpKernel/Cache/EsiListenerTest.php
  23. 1 1
      tests/Symfony/Tests/Component/HttpKernel/ResponseListenerTest.php

+ 2 - 9
src/Symfony/Bundle/FrameworkBundle/Controller/ParamConverterListener.php

@@ -23,6 +23,8 @@ use Symfony\Component\EventDispatcher\Event;
  * Converts \ReflectionParameters for Controller actions into Objects if the \ReflectionParameter have a class
  * (Typehinted).
  *
+ * The filterController method must be connected to the core.controller event.
+ *
  * @author Fabien Potencier <fabien.potencier@symfony-project.org>
  * @author Henrik Bjornskov <hb@peytz.dk>
  */
@@ -41,15 +43,6 @@ class ParamConverterListener
         $this->manager = $manager;
     }
 
-    /**
-     * @param EventDispatcher $dispatcher
-     * @param integer         $priority = 0
-     */
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        $dispatcher->connect('core.controller', array($this, 'filterController'), $priority);
-    }
-
     /**
      * @param  Event $event
      * @param  mixed $controller

+ 6 - 2
src/Symfony/Bundle/FrameworkBundle/Debug/EventDispatcher.php

@@ -16,6 +16,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\EventDispatcher\Event;
 use Symfony\Component\HttpKernel\Log\LoggerInterface;
 use Symfony\Component\HttpKernel\Debug\EventDispatcherTraceableInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * EventDispatcher extends the original EventDispatcher class to add some debugging tools.
@@ -30,10 +31,13 @@ class EventDispatcher extends BaseEventDispatcher implements EventDispatcherTrac
     /**
      * Constructor.
      *
-     * @param LoggerInterface $logger A LoggerInterface instance
+     * @param ContainerInterface $container A ContainerInterface instance
+     * @param LoggerInterface    $logger    A LoggerInterface instance
      */
-    public function __construct(LoggerInterface $logger = null)
+    public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
     {
+        parent::__construct($container);
+
         $this->logger = $logger;
         $this->called = array();
     }

+ 19 - 8
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/RegisterKernelListenersPass.php

@@ -24,14 +24,25 @@ class RegisterKernelListenersPass implements CompilerPassInterface
         }
 
         $listeners = array();
-        foreach ($container->findTaggedServiceIds('kernel.listener') as $id => $attributes) {
-            $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
-
-            if (!isset($listeners[$priority])) {
-                $listeners[$priority] = array();
+        foreach ($container->findTaggedServiceIds('kernel.listener') as $id => $events) {
+            foreach ($events as $event) {
+                $priority = isset($event['priority']) ? $event['priority'] : 0;
+                if (!isset($event['event'])) {
+                    throw new \InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "kernel.listener" tags.', $id));
+                }
+                if (!isset($event['method'])) {
+                    throw new \InvalidArgumentException(sprintf('Service "%s" must define the "method" attribute on "kernel.listener" tags.', $id));
+                }
+
+                if (!isset($listeners[$event['event']][$priority])) {
+                    if (!isset($listeners[$event['event']])) {
+                        $listeners[$event['event']] = array();
+                    }
+                    $listeners[$event['event']][$priority] = array();
+                }
+
+                $listeners[$event['event']][$priority][$id] = $event['method'];
             }
-
-            $listeners[$priority][] = new Reference($id);
         }
 
         $container
@@ -39,4 +50,4 @@ class RegisterKernelListenersPass implements CompilerPassInterface
             ->addMethodCall('registerKernelListeners', array($listeners))
         ;
     }
-}
+}

+ 35 - 4
src/Symfony/Bundle/FrameworkBundle/EventDispatcher.php

@@ -12,6 +12,7 @@
 namespace Symfony\Bundle\FrameworkBundle;
 
 use Symfony\Component\EventDispatcher\EventDispatcher as BaseEventDispatcher;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * This EventDispatcher automatically gets the kernel listeners injected
@@ -20,12 +21,42 @@ use Symfony\Component\EventDispatcher\EventDispatcher as BaseEventDispatcher;
  */
 class EventDispatcher extends BaseEventDispatcher
 {
-    public function registerKernelListeners(array $kernelListeners)
+    protected $container;
+    protected $ids;
+
+    /**
+     * Constructor.
+     *
+     * @param ContainerInterface $container A ContainerInterface instance
+     */
+    public function __construct(ContainerInterface $container)
+    {
+        $this->container = $container;
+    }
+
+    public function registerKernelListeners(array $ids)
+    {
+        $this->ids = $ids;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getListeners($name)
     {
-        foreach ($kernelListeners as $priority => $listeners) {
-            foreach ($listeners as $listener) {
-                $listener->register($this, $priority);
+        if (!isset($this->ids[$name])) {
+            return array();
+        }
+
+        $listeners = array();
+        $all = $this->ids[$name];
+        krsort($all);
+        foreach ($all as $l) {
+            foreach ($l as $id => $method) {
+                $listeners[] = array($this->container->get($id), $method);
             }
         }
+
+        return $listeners;
     }
 }

+ 2 - 11
src/Symfony/Bundle/FrameworkBundle/RequestListener.php

@@ -21,6 +21,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 /**
  * RequestListener.
  *
+ * The handle method must be connected to the core.request event.
+ *
  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  */
 class RequestListener
@@ -36,17 +38,6 @@ class RequestListener
         $this->logger = $logger;
     }
 
-    /**
-     * Registers a core.request listener.
-     *
-     * @param EventDispatcher $dispatcher An EventDispatcher instance
-     * @param integer         $priority   The priority
-     */
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        $dispatcher->connect('core.request', array($this, 'handle'), $priority);
-    }
-
     public function handle(Event $event)
     {
         $request = $event->get('request');

+ 1 - 0
src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml

@@ -10,6 +10,7 @@
 
     <services>
         <service id="debug.event_dispatcher" class="%debug.event_dispatcher.class%">
+            <argument type="service" id="service_container" />
             <argument type="service" id="logger" on-invalid="null" />
         </service>
     </services>

+ 2 - 2
src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml

@@ -12,8 +12,8 @@
     <services>
         <service id="esi" class="%esi.class%" public="false" />
 
-        <service id="esi_listener" class="%esi_listener.class%" public="false">
-          <tag name="kernel.listener" />
+        <service id="esi_listener" class="%esi_listener.class%">
+          <tag name="kernel.listener" event="core.response" method="filter" />
           <argument type="service" id="esi" on-invalid="ignore" />
         </service>
     </services>

+ 2 - 2
src/Symfony/Bundle/FrameworkBundle/Resources/config/param_converter.xml

@@ -14,8 +14,8 @@
         <service id="request.param_converter.manager" class="%request.param_converter.manager.class%" public="false" />
 
         <!-- ParamConverterListener -->
-        <service id="request.param_converter.listener" class="%request.param_converter.listener.class%" public="false">
-            <tag name="kernel.listener" />
+        <service id="request.param_converter.listener" class="%request.param_converter.listener.class%">
+            <tag name="kernel.listener" event="core.controller" method="filterController" />
             <argument type="service" id="request.param_converter.manager" />
         </service>
     </services>

+ 3 - 2
src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml

@@ -24,8 +24,9 @@
             <argument>%profiler.storage.lifetime%</argument>
         </service>
 
-        <service id="profiler_listener" class="%profiler_listener.class%" public="false">
-            <tag name="kernel.listener" />
+        <service id="profiler_listener" class="%profiler_listener.class%">
+            <tag name="kernel.listener" event="core.response" method="handleResponse" />
+            <tag name="kernel.listener" event="core.exception" method="handleException" />
             <argument type="service" id="profiler" />
             <argument type="service" id="profiler.request_matcher" on-invalid="null" />
             <argument>%profiler_listener.only_exceptions%</argument>

+ 5 - 3
src/Symfony/Bundle/FrameworkBundle/Resources/config/security.xml

@@ -154,15 +154,17 @@
             <argument type="service" id="security.role_hierarchy" />
         </service>
 
-        <service id="security.firewall" class="%security.firewall.class%" public="false">
-            <tag name="kernel.listener" priority="-128" />
+        <service id="security.firewall" class="%security.firewall.class%">
+            <tag name="kernel.listener" event="core.request" method="handle" priority="-128" />
             <argument type="service" id="security.firewall.map" />
+            <argument type="service" id="event_dispatcher" />
         </service>
+
         <service id="security.firewall.map" class="%security.firewall.map.class%" public="false">
             <argument type="service" id="service_container" />
             <argument type="collection" />
         </service>
-        
+
         <service id="security.context_listener" class="%security.context_listener.class%" public="false">
             <argument type="service" id="security.context" />
             <argument type="collection"></argument>

+ 1 - 0
src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml

@@ -15,6 +15,7 @@
 
     <services>
         <service id="event_dispatcher" class="%event_dispatcher.class%">
+            <argument type="service" id="service_container" />
         </service>
 
         <service id="error_handler" class="%error_handler.class%" public="false">

+ 6 - 6
src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml

@@ -25,19 +25,19 @@
             <argument type="service" id="logger" on-invalid="ignore" />
         </service>
 
-        <service id="request_listener" class="%request_listener.class%" public="false">
-            <tag name="kernel.listener" />
+        <service id="request_listener" class="%request_listener.class%">
+            <tag name="kernel.listener" event="core.request" method="handle" />
             <argument type="service" id="service_container" />
             <argument type="service" id="router" />
             <argument type="service" id="logger" on-invalid="ignore" />
         </service>
 
-        <service id="response_listener" class="%response_listener.class%" public="false">
-            <tag name="kernel.listener" />
+        <service id="response_listener" class="%response_listener.class%">
+            <tag name="kernel.listener" event="core.response" method="filter" />
         </service>
 
-        <service id="exception_listener" class="%exception_listener.class%" public="false">
-            <tag name="kernel.listener" priority="-128" />
+        <service id="exception_listener" class="%exception_listener.class%">
+            <tag name="kernel.listener" event="core.exception" method="handle" priority="-128" />
             <argument>%exception_listener.controller%</argument>
             <argument type="service" id="logger" on-invalid="null" />
         </service>

+ 2 - 2
src/Symfony/Bundle/WebProfilerBundle/Resources/config/toolbar.xml

@@ -10,8 +10,8 @@
     </parameters>
 
     <services>
-        <service id="debug.toolbar" class="%debug.toolbar.class%" public="false">
-            <tag name="kernel.listener" priority="-128" />
+        <service id="debug.toolbar" class="%debug.toolbar.class%">
+            <tag name="kernel.listener" event="core.response" method="handle" priority="-128" />
             <argument type="service" id="http_kernel" />
             <argument>%debug.toolbar.intercept_redirects%</argument>
         </service>

+ 2 - 11
src/Symfony/Bundle/WebProfilerBundle/WebDebugToolbarListener.php

@@ -21,6 +21,8 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
 /**
  * WebDebugToolbarListener injects the Web Debug Toolbar.
  *
+ * The handle method must be connected to the core.response event.
+ *
  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  */
 class WebDebugToolbarListener
@@ -34,17 +36,6 @@ class WebDebugToolbarListener
         $this->interceptRedirects = $interceptRedirects;
     }
 
-    /**
-     * Registers a core.response listener.
-     *
-     * @param EventDispatcher $dispatcher An EventDispatcher instance
-     * @param integer         $priority   The priority
-     */
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        $dispatcher->connect('core.response', array($this, 'handle'), $priority);
-    }
-
     public function handle(Event $event, Response $response)
     {
         if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type')) {

+ 3 - 15
src/Symfony/Component/HttpKernel/Cache/EsiListener.php

@@ -18,6 +18,8 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
 /**
  * EsiListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for ESI.
  *
+ * The filter method must be connected to the core.response event.
+ *
  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  */
 class EsiListener
@@ -35,20 +37,6 @@ class EsiListener
         $this->esi = $esi;
     }
 
-    /**
-     * Registers a core.response listener to add the Surrogate-Control header to a Response when needed.
-     *
-     * @param EventDispatcher $dispatcher An EventDispatcher instance
-     * @param integer         $priority   The priority
-     */
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        if (null !== $this->esi)
-        {
-            $dispatcher->connect('core.response', array($this, 'filter'), $priority);
-        }
-    }
-
     /**
      * Filters the Response.
      *
@@ -57,7 +45,7 @@ class EsiListener
      */
     public function filter($event, Response $response)
     {
-        if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type')) {
+        if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type') || null === $this->esi) {
             return $response;
         }
 

+ 2 - 11
src/Symfony/Component/HttpKernel/Debug/ExceptionListener.php

@@ -22,6 +22,8 @@ use Symfony\Component\HttpFoundation\Request;
 /**
  * ExceptionListener.
  *
+ * The handle method must be connected to the core.exception event.
+ *
  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  */
 class ExceptionListener
@@ -35,17 +37,6 @@ class ExceptionListener
         $this->logger = $logger;
     }
 
-    /**
-     * Registers a core.exception listener.
-     *
-     * @param EventDispatcher $dispatcher An EventDispatcher instance
-     * @param integer         $priority   The priority
-     */
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        $dispatcher->connect('core.exception', array($this, 'handle'), $priority);
-    }
-
     public function handle(Event $event)
     {
         static $handling;

+ 3 - 12
src/Symfony/Component/HttpKernel/Profiler/ProfilerListener.php

@@ -20,6 +20,9 @@ use Symfony\Component\HttpFoundation\RequestMatcherInterface;
 /**
  * ProfilerListener collects data for the current request by listening to the core.response event.
  *
+ * The handleException method must be connected to the core.exception event.
+ * The handleResponse method must be connected to the core.response event.
+ *
  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  */
 class ProfilerListener
@@ -43,18 +46,6 @@ class ProfilerListener
         $this->onlyException = $onlyException;
     }
 
-    /**
-     * Registers a core.response and core.exception listeners.
-     *
-     * @param EventDispatcher $dispatcher An EventDispatcher instance
-     * @param integer         $priority   The priority
-     */
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        $dispatcher->connect('core.exception', array($this, 'handleException'), $priority);
-        $dispatcher->connect('core.response', array($this, 'handleResponse'), $priority);
-    }
-
     /**
      * Handles the core.exception event.
      *

+ 0 - 1
src/Symfony/Component/HttpKernel/Resources/bin/packager.php

@@ -27,7 +27,6 @@ ClassCollectionLoader::load(array(
     'Symfony\\Component\\HttpKernel\\Bundle\\BundleInterface',
     'Symfony\\Component\\HttpKernel\\Debug\\ErrorHandler',
     'Symfony\\Component\\HttpKernel\\ClassCollectionLoader',
-    'Symfony\\Component\\HttpKernel\\Debug\\ExceptionListener',
 
     'Symfony\\Component\\DependencyInjection\\Container',
     'Symfony\\Component\\DependencyInjection\\ContainerAwareInterface',

+ 2 - 11
src/Symfony/Component/HttpKernel/ResponseListener.php

@@ -18,21 +18,12 @@ use Symfony\Component\HttpFoundation\Response;
 /**
  * ResponseListener fixes the Response Content-Type.
  *
+ * The filter method must be connected to the core.response event.
+ *
  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  */
 class ResponseListener
 {
-    /**
-     * Registers a core.response listener to change the Content-Type header based on the Request format.
-     *
-     * @param EventDispatcher $dispatcher An EventDispatcher instance
-     * @param integer         $priority   The priority
-     */
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        $dispatcher->connect('core.response', array($this, 'filter'), $priority);
-    }
-
     /**
      * Filters the Response.
      *

+ 4 - 13
src/Symfony/Component/HttpKernel/Security/Firewall.php

@@ -24,6 +24,8 @@ use Symfony\Component\HttpFoundation\Request;
  * (a Basic authentication for the /api, and a web based authentication for
  * everything else for instance).
  *
+ * The handle method must be connected to the core.request event.
+ *
  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  */
 class Firewall
@@ -37,22 +39,11 @@ class Firewall
      *
      * @param FirewallMap $map A FirewallMap instance
      */
-    public function __construct(FirewallMapInterface $map)
+    public function __construct(FirewallMapInterface $map, EventDispatcher $dispatcher)
     {
         $this->map = $map;
-        $this->currentListeners = array();
-    }
-
-    /**
-     * Registers a core.request listener to enforce security.
-     *
-     * @param EventDispatcher $dispatcher An EventDispatcher instance
-     * @param integer         $priority   The priority
-     */
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        $dispatcher->connect('core.request', array($this, 'handle'), $priority);
         $this->dispatcher = $dispatcher;
+        $this->currentListeners = array();
     }
 
     /**

+ 0 - 4
src/Symfony/Component/HttpKernel/bootstrap.php

@@ -232,10 +232,6 @@ class ExceptionListener
         $this->controller = $controller;
         $this->logger = $logger;
     }
-    public function register(EventDispatcher $dispatcher, $priority = 0)
-    {
-        $dispatcher->connect('core.exception', array($this, 'handle'), $priority);
-    }
     public function handle(Event $event)
     {
         static $handling;

+ 3 - 12
tests/Symfony/Tests/Component/HttpKernel/Cache/EsiListenerTest.php

@@ -24,7 +24,7 @@ class EsiListenerTest extends \PHPUnit_Framework_TestCase
     {
         $dispatcher = new EventDispatcher();
         $listener = new EsiListener(new Esi());
-        $listener->register($dispatcher);
+        $dispatcher->connect('core.response', array($listener, 'filter'));
 
         $event = new Event(null, 'core.response', array('request_type' => HttpKernelInterface::SUB_REQUEST));
         $dispatcher->filter($event, $response = new Response('foo <esi:include src="" />'));
@@ -32,20 +32,11 @@ class EsiListenerTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals('', $response->headers->get('Surrogate-Control'));
     }
 
-    public function testNothingIsRegisteredIfEsiIsNull()
-    {
-        $dispatcher = new EventDispatcher();
-        $listener = new EsiListener();
-        $listener->register($dispatcher);
-
-        $this->assertEquals(array(), $dispatcher->getListeners('core.response'));
-    }
-
     public function testFilterWhenThereIsSomeEsiIncludes()
     {
         $dispatcher = new EventDispatcher();
         $listener = new EsiListener(new Esi());
-        $listener->register($dispatcher);
+        $dispatcher->connect('core.response', array($listener, 'filter'));
 
         $event = new Event(null, 'core.response', array('request_type' => HttpKernelInterface::MASTER_REQUEST));
         $dispatcher->filter($event, $response = new Response('foo <esi:include src="" />'));
@@ -57,7 +48,7 @@ class EsiListenerTest extends \PHPUnit_Framework_TestCase
     {
         $dispatcher = new EventDispatcher();
         $listener = new EsiListener(new Esi());
-        $listener->register($dispatcher);
+        $dispatcher->connect('core.response', array($listener, 'filter'));
 
         $event = new Event(null, 'core.response', array('request_type' => HttpKernelInterface::MASTER_REQUEST));
         $dispatcher->filter($event, $response = new Response('foo'));

+ 1 - 1
tests/Symfony/Tests/Component/HttpKernel/ResponseListenerTest.php

@@ -60,7 +60,7 @@ class ResponseListenerTest extends \PHPUnit_Framework_TestCase
     {
         $dispatcher = new EventDispatcher();
         $listener = new ResponseListener();
-        $listener->register($dispatcher);
+        $dispatcher->connect('core.response', array($listener, 'filter'));
 
         return $dispatcher;
     }