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