From ddd7aac6f2d1e3b1660f38045cab4214a26f2325 Mon Sep 17 00:00:00 2001 From: Benaka Moorthi Date: Fri, 5 Jul 2013 19:44:45 -0400 Subject: Implemented custom event dispatching system for Piwik (replaced event dispatcher lib in libs/Event). Notes: - New dispatcher can execute callbacks before or after other callbacks. - It is also possible to dispatch events only to a specific set of plugins instead of all plugins. - Moved Piwik::unprefixClass to Piwik_Common::unprefixClass - Added visibility to some event handlers that were missing it. - Allowed two unit tests to fail w/ better diagnostic messages. --- core/EventDispatcher.php | 206 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 core/EventDispatcher.php (limited to 'core/EventDispatcher.php') diff --git a/core/EventDispatcher.php b/core/EventDispatcher.php new file mode 100644 index 0000000000..f39148c7a4 --- /dev/null +++ b/core/EventDispatcher.php @@ -0,0 +1,206 @@ +pendingEvents[] = array($eventName, $params); + } + + if (empty($plugins)) { + $plugins = Piwik_PluginsManager::getInstance()->getLoadedPlugins(); + } + + $callbacks = array(); + + // collect all callbacks to execute + foreach ($plugins as $plugin) { + if (is_string($plugin)) { + $plugin = Piwik_PluginsManager::getInstance()->getLoadedPlugin($plugin); + } + + $hooks = $plugin->getListHooksRegistered(); + + if (isset($hooks[$eventName])) { + list($pluginFunction, $callbackGroup) = $this->getCallbackFunctionAndGroupNumber($hooks[$eventName]); + + $callbacks[$callbackGroup][] = array($plugin, $pluginFunction); + } + } + + if (isset($this->extraObservers[$eventName])) { + foreach ($this->extraObservers[$eventName] as $callbackInfo) { + list($callback, $callbackGroup) = $this->getCallbackFunctionAndGroupNumber($callbackInfo); + + $callbacks[$callbackGroup][] = $callback; + } + } + + // execute callbacks in order + foreach ($callbacks as $callbackGroup) { + foreach ($callbackGroup as $callback) { + call_user_func_array($callback, $params); + } + } + } + + /** + * Associates a callback that is not a plugin class method with an event + * name. + * + * @param string $eventName + * @param array $callback This can be a normal PHP callback or an array + * that looks like this: + * array( + * 'function' => $callback, + * 'before' => true + * ) + * or this: + * array( + * 'function' => $callback, + * 'after' => true + * ) + * If 'before' is set, the callback will be executed + * before normal & 'after' ones. If 'after' then it + * will be executed after normal ones. + */ + public function addObserver($eventName, $callback) + { + $this->extraObservers[$eventName][] = $callback; + } + + /** + * Removes all registered observers for an event name. Only used for testing. + * + * @param string $eventName + */ + public function clearObservers($eventName) + { + $this->extraObservers[$eventName] = array(); + } + + /** + * Re-posts all pending events to the given plugin. + * + * @param Piwik_Plugin $plugin + */ + public function postPendingEventsTo($plugin) + { + foreach ($this->pendingEvents as $eventInfo) { + list($eventName, $eventParams) = $eventInfo; + $this->postEvent($eventName, $eventParams, $pending = false, array($plugin)); + } + } + + private function getCallbackFunctionAndGroupNumber($hookInfo) + { + if (is_array($hookInfo) + && !empty($hookInfo['function']) + ) { + $pluginFunction = $hookInfo['function']; + if (!empty($hookInfo['before'])) { + $callbackGroup = self::EVENT_CALLBACK_GROUP_FIRST; + } else if (!empty($hookInfo['after'])) { + $callbackGroup = self::EVENT_CALLBACK_GROUP_SECOND; + } else { + $callbackGroup = self::EVENT_CALLBACK_GROUP_THIRD; + } + } else { + $pluginFunction = $hookInfo; + $callbackGroup = self::EVENT_CALLBACK_GROUP_SECOND; + } + + return array($pluginFunction, $callbackGroup); + } +} + +/** + * Post an event to the dispatcher which will notice the observers. + * + * @param string $eventName The event name. + * @param array $params The parameter array to forward to observer callbacks. + * @return void + */ +function Piwik_PostEvent($eventName, $params = array(), $pending = false, $plugins = null) +{ + Piwik_EventDispatcher::getInstance()->postEvent($eventName, $params, $pending, $plugins); +} + +/** + * Register an action to execute for a given event + * + * @param string $eventName Name of event + * @param function $function Callback hook + */ +function Piwik_AddAction($eventName, $function) +{ + Piwik_EventDispatcher::getInstance()->addObserver($eventName, $function); +} -- cgit v1.2.3