Commit | Line | Data |
---|---|---|
762dc04d TO |
1 | <?php |
2 | ||
3 | namespace Civi\Core; | |
4 | ||
5 | use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; | |
6 | use Symfony\Component\EventDispatcher\Event; | |
7 | ||
8 | /** | |
9 | * Class CiviEventDispatcher | |
10 | * @package Civi\Core | |
11 | * | |
12 | * The CiviEventDispatcher is a Symfony dispatcher. Additionally, if an event | |
13 | * follows the naming convention of "hook_*", then it will also be dispatched | |
14 | * through CRM_Utils_Hook::invoke(). | |
15 | * | |
16 | * @see \CRM_Utils_Hook | |
17 | */ | |
18 | class CiviEventDispatcher extends ContainerAwareEventDispatcher { | |
19 | ||
20 | const DEFAULT_HOOK_PRIORITY = -100; | |
21 | ||
22 | /** | |
23 | * Track the list of hook-events for which we have autoregistered | |
24 | * the hook adapter. | |
25 | * | |
26 | * @var array | |
27 | * Array(string $eventName => trueish). | |
28 | */ | |
c64f69d9 | 29 | private $autoListeners = []; |
762dc04d TO |
30 | |
31 | /** | |
32 | * Determine whether $eventName should delegate to the CMS hook system. | |
33 | * | |
34 | * @param string $eventName | |
35 | * Ex: 'civi.token.eval', 'hook_civicrm_post`. | |
36 | * @return bool | |
37 | */ | |
38 | protected function isHookEvent($eventName) { | |
39 | return (substr($eventName, 0, 5) === 'hook_') && (strpos($eventName, '::') === FALSE); | |
40 | } | |
41 | ||
42 | /** | |
43 | * @inheritDoc | |
44 | */ | |
45 | public function dispatch($eventName, Event $event = NULL) { | |
46 | $this->bindPatterns($eventName); | |
47 | return parent::dispatch($eventName, $event); | |
48 | } | |
49 | ||
50 | /** | |
51 | * @inheritDoc | |
52 | */ | |
53 | public function getListeners($eventName = NULL) { | |
54 | $this->bindPatterns($eventName); | |
55 | return parent::getListeners($eventName); | |
56 | } | |
57 | ||
58 | /** | |
59 | * @inheritDoc | |
60 | */ | |
61 | public function hasListeners($eventName = NULL) { | |
62 | // All hook_* events have default listeners, so hasListeners(NULL) is a truism. | |
63 | return ($eventName === NULL || $this->isHookEvent($eventName)) | |
64 | ? TRUE : parent::hasListeners($eventName); | |
65 | } | |
66 | ||
67 | /** | |
68 | * Invoke hooks using an event object. | |
69 | * | |
70 | * @param \Civi\Core\Event\GenericHookEvent $event | |
71 | * @param string $eventName | |
72 | * Ex: 'hook_civicrm_dashboard'. | |
73 | */ | |
74 | public static function delegateToUF($event, $eventName) { | |
75 | $hookName = substr($eventName, 5); | |
76 | $hooks = \CRM_Utils_Hook::singleton(); | |
77 | $params = $event->getHookValues(); | |
78 | $count = count($params); | |
79 | ||
80 | switch ($count) { | |
81 | case 0: | |
82 | $fResult = $hooks->invokeViaUF($count, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, $hookName); | |
83 | break; | |
84 | ||
85 | case 1: | |
86 | $fResult = $hooks->invokeViaUF($count, $params[0], \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, $hookName); | |
87 | break; | |
88 | ||
89 | case 2: | |
90 | $fResult = $hooks->invokeViaUF($count, $params[0], $params[1], \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, $hookName); | |
91 | break; | |
92 | ||
93 | case 3: | |
94 | $fResult = $hooks->invokeViaUF($count, $params[0], $params[1], $params[2], \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, $hookName); | |
95 | break; | |
96 | ||
97 | case 4: | |
98 | $fResult = $hooks->invokeViaUF($count, $params[0], $params[1], $params[2], $params[3], \CRM_Utils_Hook::$_nullObject, \CRM_Utils_Hook::$_nullObject, $hookName); | |
99 | break; | |
100 | ||
101 | case 5: | |
102 | $fResult = $hooks->invokeViaUF($count, $params[0], $params[1], $params[2], $params[3], $params[4], \CRM_Utils_Hook::$_nullObject, $hookName); | |
103 | break; | |
104 | ||
105 | case 6: | |
106 | $fResult = $hooks->invokeViaUF($count, $params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $hookName); | |
107 | break; | |
108 | ||
109 | default: | |
110 | throw new \RuntimeException("hook_{$hookName} cannot support more than 6 parameters"); | |
111 | } | |
112 | ||
113 | $event->addReturnValues($fResult); | |
114 | } | |
115 | ||
116 | /** | |
117 | * @param string $eventName | |
118 | * Ex: 'civi.api.resolve' or 'hook_civicrm_dashboard'. | |
119 | */ | |
120 | protected function bindPatterns($eventName) { | |
121 | if ($eventName !== NULL && !isset($this->autoListeners[$eventName])) { | |
122 | $this->autoListeners[$eventName] = 1; | |
123 | if ($this->isHookEvent($eventName)) { | |
124 | // WISHLIST: For native extensions (and possibly D6/D7/D8/BD), enumerate | |
125 | // the listeners and list them one-by-one. This would make it easier to | |
126 | // inspect via "cv debug:event-dispatcher". | |
c64f69d9 | 127 | $this->addListener($eventName, [ |
762dc04d TO |
128 | '\Civi\Core\CiviEventDispatcher', |
129 | 'delegateToUF', | |
c64f69d9 | 130 | ], self::DEFAULT_HOOK_PRIORITY); |
762dc04d TO |
131 | } |
132 | } | |
133 | } | |
134 | ||
135 | } |