/libraries/joomla/event/dispatcher.php

https://gitlab.com/vitaliylukin91/alex-lavka · PHP · 278 lines · 134 code · 33 blank · 111 comment · 21 complexity · 25a1351f58781b353f52c0bf88c19a67 MD5 · raw file

  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Event
  5. *
  6. * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. /**
  11. * Class to handle dispatching of events.
  12. *
  13. * This is the Observable part of the Observer design pattern
  14. * for the event architecture.
  15. *
  16. * @link https://docs.joomla.org/Tutorial:Plugins Plugin tutorials
  17. * @see JPlugin
  18. * @since 12.1
  19. */
  20. class JEventDispatcher extends JObject
  21. {
  22. /**
  23. * An array of Observer objects to notify
  24. *
  25. * @var array
  26. * @since 11.3
  27. */
  28. protected $_observers = array();
  29. /**
  30. * The state of the observable object
  31. *
  32. * @var mixed
  33. * @since 11.3
  34. */
  35. protected $_state = null;
  36. /**
  37. * A multi dimensional array of [function][] = key for observers
  38. *
  39. * @var array
  40. * @since 11.3
  41. */
  42. protected $_methods = array();
  43. /**
  44. * Stores the singleton instance of the dispatcher.
  45. *
  46. * @var JEventDispatcher
  47. * @since 11.3
  48. */
  49. protected static $instance = null;
  50. /**
  51. * Returns the global Event Dispatcher object, only creating it
  52. * if it doesn't already exist.
  53. *
  54. * @return JEventDispatcher The EventDispatcher object.
  55. *
  56. * @since 11.1
  57. */
  58. public static function getInstance()
  59. {
  60. if (self::$instance === null)
  61. {
  62. self::$instance = new static;
  63. }
  64. return self::$instance;
  65. }
  66. /**
  67. * Get the state of the JEventDispatcher object
  68. *
  69. * @return mixed The state of the object.
  70. *
  71. * @since 11.3
  72. */
  73. public function getState()
  74. {
  75. return $this->_state;
  76. }
  77. /**
  78. * Registers an event handler to the event dispatcher
  79. *
  80. * @param string $event Name of the event to register handler for
  81. * @param string $handler Name of the event handler
  82. *
  83. * @return void
  84. *
  85. * @since 11.1
  86. * @throws InvalidArgumentException
  87. */
  88. public function register($event, $handler)
  89. {
  90. // Are we dealing with a class or callback type handler?
  91. if (is_callable($handler))
  92. {
  93. // Ok, function type event handler... let's attach it.
  94. $method = array('event' => $event, 'handler' => $handler);
  95. $this->attach($method);
  96. }
  97. elseif (class_exists($handler))
  98. {
  99. // Ok, class type event handler... let's instantiate and attach it.
  100. $this->attach(new $handler($this));
  101. }
  102. else
  103. {
  104. throw new InvalidArgumentException('Invalid event handler.');
  105. }
  106. }
  107. /**
  108. * Triggers an event by dispatching arguments to all observers that handle
  109. * the event and returning their return values.
  110. *
  111. * @param string $event The event to trigger.
  112. * @param array $args An array of arguments.
  113. *
  114. * @return array An array of results from each function call.
  115. *
  116. * @since 11.1
  117. */
  118. public function trigger($event, $args = array())
  119. {
  120. $result = array();
  121. /*
  122. * If no arguments were passed, we still need to pass an empty array to
  123. * the call_user_func_array function.
  124. */
  125. $args = (array) $args;
  126. $event = strtolower($event);
  127. // Check if any plugins are attached to the event.
  128. if (!isset($this->_methods[$event]) || empty($this->_methods[$event]))
  129. {
  130. // No Plugins Associated To Event!
  131. return $result;
  132. }
  133. // Loop through all plugins having a method matching our event
  134. foreach ($this->_methods[$event] as $key)
  135. {
  136. // Check if the plugin is present.
  137. if (!isset($this->_observers[$key]))
  138. {
  139. continue;
  140. }
  141. // Fire the event for an object based observer.
  142. if (is_object($this->_observers[$key]))
  143. {
  144. $args['event'] = $event;
  145. $value = $this->_observers[$key]->update($args);
  146. }
  147. // Fire the event for a function based observer.
  148. elseif (is_array($this->_observers[$key]))
  149. {
  150. $value = call_user_func_array($this->_observers[$key]['handler'], $args);
  151. }
  152. if (isset($value))
  153. {
  154. $result[] = $value;
  155. }
  156. }
  157. return $result;
  158. }
  159. /**
  160. * Attach an observer object
  161. *
  162. * @param object $observer An observer object to attach
  163. *
  164. * @return void
  165. *
  166. * @since 11.3
  167. */
  168. public function attach($observer)
  169. {
  170. if (is_array($observer))
  171. {
  172. if (!isset($observer['handler']) || !isset($observer['event']) || !is_callable($observer['handler']))
  173. {
  174. return;
  175. }
  176. // Make sure we haven't already attached this array as an observer
  177. foreach ($this->_observers as $check)
  178. {
  179. if (is_array($check) && $check['event'] == $observer['event'] && $check['handler'] == $observer['handler'])
  180. {
  181. return;
  182. }
  183. }
  184. $this->_observers[] = $observer;
  185. $methods = array($observer['event']);
  186. }
  187. else
  188. {
  189. if (!($observer instanceof JEvent))
  190. {
  191. return;
  192. }
  193. // Make sure we haven't already attached this object as an observer
  194. $class = get_class($observer);
  195. foreach ($this->_observers as $check)
  196. {
  197. if ($check instanceof $class)
  198. {
  199. return;
  200. }
  201. }
  202. $this->_observers[] = $observer;
  203. $methods = array_diff(get_class_methods($observer), get_class_methods('JPlugin'));
  204. }
  205. end($this->_observers);
  206. $key = key($this->_observers);
  207. foreach ($methods as $method)
  208. {
  209. $method = strtolower($method);
  210. if (!isset($this->_methods[$method]))
  211. {
  212. $this->_methods[$method] = array();
  213. }
  214. $this->_methods[$method][] = $key;
  215. }
  216. }
  217. /**
  218. * Detach an observer object
  219. *
  220. * @param object $observer An observer object to detach.
  221. *
  222. * @return boolean True if the observer object was detached.
  223. *
  224. * @since 11.3
  225. */
  226. public function detach($observer)
  227. {
  228. $retval = false;
  229. $key = array_search($observer, $this->_observers);
  230. if ($key !== false)
  231. {
  232. unset($this->_observers[$key]);
  233. $retval = true;
  234. foreach ($this->_methods as &$method)
  235. {
  236. $k = array_search($key, $method);
  237. if ($k !== false)
  238. {
  239. unset($method[$k]);
  240. }
  241. }
  242. }
  243. return $retval;
  244. }
  245. }