Merge pull request #23215 from eileenmcnaughton/test_amount
[civicrm-core.git] / Civi / Core / CiviEventDispatcher.php
index ac104537d81bfe8968015ea37004a6447634aeb1..f2ddb6431ef63e8eb784b2bf7d059c3f04410e2f 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Civi\Core;
 
+use Civi\Core\Event\HookStyleListener;
 use Symfony\Component\EventDispatcher\EventDispatcher;
 use Symfony\Component\EventDispatcher\Event;
 
@@ -61,6 +62,80 @@ class CiviEventDispatcher extends EventDispatcher {
     return (substr($eventName, 0, 5) === 'hook_') && (strpos($eventName, '::') === FALSE);
   }
 
+  /**
+   * Adds a series of event listeners from a subscriber object.
+   *
+   * This is particularly useful if you want to register the subscriber without
+   * materializing the subscriber object.
+   *
+   * @param string $subscriber
+   *   Service ID of the subscriber.
+   * @param array $events
+   *   List of events/methods/priorities.
+   * @see \Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents()
+   */
+  public function addSubscriberServiceMap(string $subscriber, array $events) {
+    foreach ($events as $eventName => $params) {
+      if (\is_string($params)) {
+        $this->addListenerService($eventName, [$subscriber, $params]);
+      }
+      elseif (\is_string($params[0])) {
+        $this->addListenerService($eventName, [$subscriber, $params[0]], isset($params[1]) ? $params[1] : 0);
+      }
+      else {
+        foreach ($params as $listener) {
+          $this->addListenerService($eventName, [$subscriber, $listener[0]], isset($listener[1]) ? $listener[1] : 0);
+        }
+      }
+    }
+  }
+
+  /**
+   * Add a test listener.
+   *
+   * @param string $eventName
+   *   Ex: 'civi.internal.event'
+   *   Ex: 'hook_civicrm_publicEvent'
+   *   Ex: '&hook_civicrm_publicEvent' (an alias for 'hook_civicrm_publicEvent' in which the listener abides hook-style ordered parameters).
+   *        This notation is handy when attaching via listener-maps (e.g. `getSubscribedEvents()`).
+   * @param callable $listener
+   * @param int $priority
+   */
+  public function addListener($eventName, $listener, $priority = 0) {
+    if ($eventName[0] === '&') {
+      $eventName = substr($eventName, 1);
+      $listener = new HookStyleListener($listener);
+    }
+    parent::addListener($eventName, $listener, $priority);
+  }
+
+  /**
+   * Adds a series of event listeners from methods in a class.
+   *
+   * @param string|object $target
+   *   The object/class which will receive the notifications.
+   *   Use a string (class-name) if the listeners are static methods.
+   *   Use an object-instance if the listeners are regular methods.
+   * @param array $events
+   *   List of events/methods/priorities.
+   * @see \Symfony\Component\EventDispatcher\EventSubscriberInterface::getSubscribedEvents()
+   */
+  public function addListenerMap($target, array $events) {
+    foreach ($events as $eventName => $params) {
+      if (\is_string($params)) {
+        $this->addListener($eventName, [$target, $params]);
+      }
+      elseif (\is_string($params[0])) {
+        $this->addListener($eventName, [$target, $params[0]], isset($params[1]) ? $params[1] : 0);
+      }
+      else {
+        foreach ($params as $listener) {
+          $this->addListener($eventName, [$target, $listener[0]], isset($listener[1]) ? $listener[1] : 0);
+        }
+      }
+    }
+  }
+
   /**
    * Adds a service as event listener.
    *
@@ -80,13 +155,7 @@ class CiviEventDispatcher extends EventDispatcher {
       throw new \InvalidArgumentException('Expected an array("service", "method") argument');
     }
 
-    $this->addListener($eventName, function($event) use ($callback) {
-      static $svc;
-      if ($svc === NULL) {
-        $svc = \Civi::container()->get($callback[0]);
-      }
-      return call_user_func([$svc, $callback[1]], $event);
-    }, $priority);
+    $this->addListener($eventName, new \Civi\Core\Event\ServiceListener($callback), $priority);
   }
 
   /**