Ver Fonte

[DoctrineBundle] refactored event listeners/subscribers to not rely on parameter name conventions

 * Doctrine event subscribers now all use the same "doctrine.event_subscriber" tag. To specify a connection,
   use the "connection" attribute.

 * Doctrine event listeners now all use the same "doctrine.event_listener" tag. To specify a connection,
   use the "connection" attribute.
Fabien Potencier há 14 anos atrás
pai
commit
01695bc654

+ 30 - 0
UPDATE.md

@@ -9,6 +9,36 @@ timeline closely anyway.
 beta1 to beta2
 --------------
 
+* Doctrine event subscribers now use a unique "doctrine.event_subscriber" tag.
+  Doctrine event listeners also use a unique "doctrine.event_listener" tag. To
+  specify a connection, use the optional "connection" attribute.
+
+    Before:
+
+        listener:
+            class: MyEventListener
+            tags:
+                - { name: doctrine.common.event_listener, event: name }
+                - { name: doctrine.dbal.default_event_listener, event: name }
+        subscriber:
+            class: MyEventSubscriber
+            tags:
+                - { name: doctrine.common.event_subscriber }
+                - { name: doctrine.dbal.default_event_subscriber }
+
+    After:
+
+        listener:
+            class: MyEventListener
+            tags:
+                - { name: doctrine.event_listener, event: name }                      # register for all connections
+                - { name: doctrine.event_listener, event: name, connection: default } # only for the default connection
+        subscriber:
+            class: MyEventSubscriber
+            tags:
+                - { name: doctrine.event_subscriber }                      # register for all connections
+                - { name: doctrine.event_subscriber, connection: default } # only for the default connection
+
 * The `doctrine.orm.entity_managers` is now hash of entity manager names/ids pairs:
 
     Before: array('default', 'foo')

+ 62 - 32
src/Symfony/Bundle/DoctrineBundle/DependencyInjection/Compiler/RegisterEventListenersAndSubscribersPass.php

@@ -9,55 +9,85 @@ use Symfony\Component\DependencyInjection\DefinitionDecorator;
 
 class RegisterEventListenersAndSubscribersPass implements CompilerPassInterface
 {
-    protected $container;
+    private $container;
+    private $connections;
+    private $eventManagers;
 
     public function process(ContainerBuilder $container)
     {
         $this->container = $container;
-        foreach ($container->getDefinitions() as $id => $definition) {
-            if (!$definition instanceof DefinitionDecorator || 'doctrine.dbal.connection.event_manager' !== $definition->getParent()) {
-                continue;
-            }
+        $this->connections = $container->getParameter('doctrine.dbal.connections');
+
+        foreach ($container->findTaggedServiceIds('doctrine.event_subscriber') as $subscriberId => $instances) {
+            $this->registerSubscriber($subscriberId, $instances);
+        }
 
-            $prefix = substr($id, 0, -strlen('_connection.event_manager'));
-            $this->registerListeners($prefix, $definition);
-            $this->registerSubscribers($prefix, $definition);
+        foreach ($container->findTaggedServiceIds('doctrine.event_listener') as $listenerId => $instances) {
+            $this->registerListener($listenerId, $instances);
         }
     }
 
-    protected function registerSubscribers($prefix, $definition)
+    protected function registerSubscriber($subscriberId, $instances)
     {
-        $subscribers = array_merge(
-            $this->container->findTaggedServiceIds('doctrine.common.event_subscriber'),
-            $this->container->findTaggedServiceIds($prefix.'_event_subscriber')
-        );
+        $connections = array();
+        foreach ($instances as $attributes) {
+            if (isset($attributes['connection'])) {
+                $connections[] = $attributes['connection'];
+            } else {
+                $connections = array_keys($this->connections);
+                break;
+            }
+        }
 
-        foreach ($subscribers as $id => $instances) {
-            $definition->addMethodCall('addEventSubscriber', array(new Reference($id)));
+        foreach ($connections as $name) {
+            $this->getEventManager($name)->addMethodCall('addEventSubscriber', array(new Reference($subscriberId)));
         }
     }
 
-    protected function registerListeners($prefix, $definition)
+    protected function registerListener($listenerId, $instances)
     {
-        $listeners = array_merge(
-            $this->container->findTaggedServiceIds('doctrine.common.event_listener'),
-            $this->container->findTaggedServiceIds($prefix.'_event_listener')
-        );
-
-        foreach ($listeners as $listenerId => $instances) {
-            $events = array();
-            foreach ($instances as $attributes) {
-                if (isset($attributes['event'])) {
-                    $events[] = $attributes['event'];
+        $connections = array();
+        foreach ($instances as $attributes) {
+            if (!isset($attributes['event'])) {
+                throw new \InvalidArgumentException(sprintf('Doctrine event listener "%s" must specify the "event" attribute.', $listenerId));
+            }
+
+            if (isset($attributes['connection'])) {
+                $cs = array($attributes['connection']);
+            } else {
+                $cs = array_keys($this->connections);
+            }
+
+            foreach ($cs as $connection) {
+                if (!is_array($connections[$connection])) {
+                    $connections[$connection] = array();
                 }
+                $connections[$connection][] = $attributes['event'];
             }
+        }
+
+        foreach ($connections as $name => $events) {
+            $this->getEventManager($name)->addMethodCall('addEventListener', array(
+                array_unique($events),
+                new Reference($listenerId),
+            ));
+        }
+    }
 
-            if (0 < count($events)) {
-                $definition->addMethodCall('addEventListener', array(
-                    $events,
-                    new Reference($listenerId),
-                ));
+    private function getEventManager($name)
+    {
+        if (null === $this->eventManagers) {
+            $this->eventManagers = array();
+            foreach ($this->connections as $n => $id) {
+                $arguments = $this->container->getDefinition($id)->getArguments();
+                $this->eventManagers[$n] = $this->container->getDefinition((string) $arguments[2]);
             }
         }
+
+        if (!isset($this->eventManagers[$name])) {
+            throw new \InvalidArgumentException(sprintf('Doctrine connection "%s" does not exist but is referenced in the "%s" event listener.', $name, $listenerId));
+        }
+
+        return $this->eventManagers[$name];
     }
-}
+}

+ 1 - 1
src/Symfony/Bundle/DoctrineBundle/DependencyInjection/DoctrineExtension.php

@@ -108,7 +108,7 @@ class DoctrineExtension extends AbstractDoctrineExtension
                 $mysqlSessionInit = new Definition('%doctrine.dbal.events.mysql_session_init.class%');
                 $mysqlSessionInit->setArguments(array($connection['charset']));
                 $mysqlSessionInit->setPublic(false);
-                $mysqlSessionInit->addTag(sprintf('doctrine.dbal.%s_event_subscriber', $name));
+                $mysqlSessionInit->addTag('doctrine.event_subscriber', array('connection' => $name));
 
                 $container->setDefinition(
                     sprintf('doctrine.dbal.%s_connection.events.mysqlsessioninit', $name),