PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/core/EventDispatcher.php

https://github.com/CodeYellowBV/piwik
PHP | 186 lines | 85 code | 23 blank | 78 comment | 13 complexity | ad7a4770656262ada8c14b8e298e3a91 MD5 | raw file
Possible License(s): LGPL-3.0, JSON, MIT, GPL-3.0, LGPL-2.1, GPL-2.0, AGPL-1.0, BSD-2-Clause, BSD-3-Clause
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik;
  10. use Piwik\Plugin;
  11. /**
  12. * This class allows code to post events from anywhere in Piwik and for
  13. * plugins to associate callbacks to be executed when events are posted.
  14. *
  15. * @method static \Piwik\EventDispatcher getInstance()
  16. */
  17. class EventDispatcher extends Singleton
  18. {
  19. // implementation details for postEvent
  20. const EVENT_CALLBACK_GROUP_FIRST = 0;
  21. const EVENT_CALLBACK_GROUP_SECOND = 1;
  22. const EVENT_CALLBACK_GROUP_THIRD = 2;
  23. /**
  24. * Array of observers (callbacks attached to events) that are not methods
  25. * of plugin classes.
  26. *
  27. * @var array
  28. */
  29. private $extraObservers = array();
  30. /**
  31. * Array storing information for all pending events. Each item in the array
  32. * will be an array w/ two elements:
  33. *
  34. * array(
  35. * 'Event.Name', // the event name
  36. * array('event', 'parameters') // the parameters to pass to event observers
  37. * )
  38. *
  39. * @var array
  40. */
  41. private $pendingEvents = array();
  42. /**
  43. * Triggers an event, executing all callbacks associated with it.
  44. *
  45. * @param string $eventName The name of the event, ie, API.getReportMetadata.
  46. * @param array $params The parameters to pass to each callback when executing.
  47. * @param bool $pending Whether this event should be posted again for plugins
  48. * loaded after the event is fired.
  49. * @param array|null $plugins The plugins to post events to. If null, the event
  50. * is posted to all plugins. The elements of this array
  51. * can be either the Plugin objects themselves
  52. * or their string names.
  53. */
  54. public function postEvent($eventName, $params, $pending = false, $plugins = null)
  55. {
  56. if ($pending) {
  57. $this->pendingEvents[] = array($eventName, $params);
  58. }
  59. if (empty($plugins)) {
  60. $plugins = \Piwik\Plugin\Manager::getInstance()->getPluginsLoadedAndActivated();
  61. }
  62. $callbacks = array();
  63. // collect all callbacks to execute
  64. foreach ($plugins as $plugin) {
  65. if (is_string($plugin)) {
  66. $plugin = \Piwik\Plugin\Manager::getInstance()->getLoadedPlugin($plugin);
  67. }
  68. $hooks = $plugin->getListHooksRegistered();
  69. if (isset($hooks[$eventName])) {
  70. list($pluginFunction, $callbackGroup) = $this->getCallbackFunctionAndGroupNumber($hooks[$eventName]);
  71. $callbacks[$callbackGroup][] = is_string($pluginFunction) ? array($plugin, $pluginFunction) : $pluginFunction;
  72. }
  73. }
  74. if (isset($this->extraObservers[$eventName])) {
  75. foreach ($this->extraObservers[$eventName] as $callbackInfo) {
  76. list($callback, $callbackGroup) = $this->getCallbackFunctionAndGroupNumber($callbackInfo);
  77. $callbacks[$callbackGroup][] = $callback;
  78. }
  79. }
  80. // execute callbacks in order
  81. foreach ($callbacks as $callbackGroup) {
  82. foreach ($callbackGroup as $callback) {
  83. call_user_func_array($callback, $params);
  84. }
  85. }
  86. }
  87. /**
  88. * Associates a callback that is not a plugin class method with an event
  89. * name.
  90. *
  91. * @param string $eventName
  92. * @param array|callable $callback This can be a normal PHP callback or an array
  93. * that looks like this:
  94. * array(
  95. * 'function' => $callback,
  96. * 'before' => true
  97. * )
  98. * or this:
  99. * array(
  100. * 'function' => $callback,
  101. * 'after' => true
  102. * )
  103. * If 'before' is set, the callback will be executed
  104. * before normal & 'after' ones. If 'after' then it
  105. * will be executed after normal ones.
  106. */
  107. public function addObserver($eventName, $callback)
  108. {
  109. $this->extraObservers[$eventName][] = $callback;
  110. }
  111. /**
  112. * Removes all registered extra observers for an event name. Only used for testing.
  113. *
  114. * @param string $eventName
  115. */
  116. public function clearObservers($eventName)
  117. {
  118. $this->extraObservers[$eventName] = array();
  119. }
  120. /**
  121. * Removes all registered extra observers. Only used for testing.
  122. */
  123. public function clearAllObservers()
  124. {
  125. foreach ($this->extraObservers as $eventName => $eventObservers) {
  126. if (strpos($eventName, 'Log.format') === 0) {
  127. continue;
  128. }
  129. $this->extraObservers[$eventName] = array();
  130. }
  131. }
  132. /**
  133. * Re-posts all pending events to the given plugin.
  134. *
  135. * @param Plugin $plugin
  136. */
  137. public function postPendingEventsTo($plugin)
  138. {
  139. foreach ($this->pendingEvents as $eventInfo) {
  140. list($eventName, $eventParams) = $eventInfo;
  141. $this->postEvent($eventName, $eventParams, $pending = false, array($plugin));
  142. }
  143. }
  144. private function getCallbackFunctionAndGroupNumber($hookInfo)
  145. {
  146. if (is_array($hookInfo)
  147. && !empty($hookInfo['function'])
  148. ) {
  149. $pluginFunction = $hookInfo['function'];
  150. if (!empty($hookInfo['before'])) {
  151. $callbackGroup = self::EVENT_CALLBACK_GROUP_FIRST;
  152. } else if (!empty($hookInfo['after'])) {
  153. $callbackGroup = self::EVENT_CALLBACK_GROUP_SECOND;
  154. } else {
  155. $callbackGroup = self::EVENT_CALLBACK_GROUP_THIRD;
  156. }
  157. } else {
  158. $pluginFunction = $hookInfo;
  159. $callbackGroup = self::EVENT_CALLBACK_GROUP_SECOND;
  160. }
  161. return array($pluginFunction, $callbackGroup);
  162. }
  163. }