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