PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / libraries / adapter / event / dispatcher.php
vikappointments / libraries / adapter / event Last commit date
dispatcher.php 3 days ago event.php 3 days ago pluginhelper.php 3 days ago
dispatcher.php
286 lines
1 <?php
2 /**
3 * @package VikWP - Libraries
4 * @subpackage adapter.event
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 JLoader::import('adapter.event.event');
15
16 /**
17 * Class to handle dispatching of events.
18 *
19 * @since 10.1.11
20 */
21 class JEventDispatcher
22 {
23 /**
24 * Stores the singleton instance of the dispatcher.
25 *
26 * @var JEventDispatcher
27 */
28 protected static $instance = null;
29
30 /**
31 * A list of observed classes.
32 *
33 * @var string
34 */
35 protected $observers = array();
36
37 /**
38 * Returns the global Event Dispatcher object, only creating it
39 * if it doesn't already exist.
40 *
41 * @return JEventDispatcher The EventDispatcher object.
42 */
43 public static function getInstance()
44 {
45 if (self::$instance === null)
46 {
47 self::$instance = new static();
48 }
49
50 return self::$instance;
51 }
52
53 /**
54 * Triggers an event by dispatching arguments to all observers that handle
55 * the event and returning their return values.
56 *
57 * @param string $event The event to trigger.
58 * @param array $args An array of arguments.
59 *
60 * @return array An array of results from each called function.
61 */
62 public function trigger($event, $args = array())
63 {
64 // make sure we are passing an array of arguments
65 $args = (array) $args;
66
67 // Push an empty value at the beginning of the list for being
68 // manipulated at every execution of the filter.
69 array_unshift($args, null);
70
71 /**
72 * Check whether the specified event uses the Joomla notation.
73 * In that case, rebuild the event to look more similar to
74 * WordPress hooks.
75 *
76 * @since 10.1.32
77 */
78 if (preg_match("/^on[A-Z]/", $event))
79 {
80 $bc = $event;
81
82 // obtain WP hook version
83 $event = $this->getHook($event);
84
85 // check whether someone is using a deprecated hook
86 if (has_filter($bc))
87 {
88 // trigger warning to inform the user that a manual adjustment is needed
89 trigger_error(
90 sprintf('expected <b>%s</b> hook, <b>%s</b> given', $event, $bc),
91 E_USER_WARNING
92 );
93
94 /**
95 * Trigger the event for backward compatibility.
96 * Assign the returned value to the first argument,
97 * so that other plugins assigned to the correct
98 * hook will be able to manipulate it.
99 *
100 * @since 10.1.32
101 *
102 * @deprecated 10.2 Use the correct hook instead.
103 */
104 $args[0] = apply_filters_ref_array($bc, $args);
105 }
106 }
107
108 /**
109 * Trigger the event.
110 * Use `apply_filters_ref_array` instead of `do_action_ref_array`
111 * to start supporting return values.
112 *
113 * @since 10.1.23
114 */
115 $return = apply_filters_ref_array($event, $args);
116
117 if (is_null($return))
118 {
119 // return an empty list as none manipulated the return value
120 return array();
121 }
122
123 // push the returned value within a list for Joomla standards
124 return array($return);
125 }
126
127 /**
128 * Registers an event handler to the event dispatcher
129 *
130 * @param string $event Name of the event to register handler for.
131 * @param string $handler Name of the event handler.
132 *
133 * @return void
134 *
135 * @since 10.1.30
136 * @throws InvalidArgumentException
137 */
138 public function register($event, $handler)
139 {
140 // are we dealing with a class or callback type handler?
141 if (is_callable($handler))
142 {
143 // function type event handler, let's attach it
144 $method = array('event' => $event, 'handler' => $handler);
145 $this->attach($method);
146 }
147 else if (class_exists($handler))
148 {
149 // class type event handler, let's instantiate and attach it
150 $this->attach(new $handler($this));
151 }
152 else
153 {
154 throw new InvalidArgumentException('Invalid event handler.');
155 }
156 }
157
158 /**
159 * Attach an observer object.
160 *
161 * @param mixed $observer An observer object to attach.
162 *
163 * @return void
164 *
165 * @since 10.1.29
166 */
167 public function attach($observer)
168 {
169 if (is_array($observer))
170 {
171 if (!isset($observer['handler']) || !isset($observer['event']) || !is_callable($observer['handler']))
172 {
173 return;
174 }
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 // callback already registered
182 return;
183 }
184 }
185
186 // obtain callback reflection and retrieve arguments
187 $reflection = new ReflectionFunction($observer['handler']);
188 $params = $reflection->getParameters();
189
190 // Register filter.
191 // Always increase parameters counter by one in order to
192 // accept the return value, which is never passed on Joomla.
193 add_filter($observer['event'], $observer['handler'], 10, count($params) + 1);
194 }
195 else
196 {
197 // make sure we haven't already attached this object as an observer
198 $class = get_class($observer);
199
200 foreach ($this->observers as $check)
201 {
202 if ($check instanceof $class)
203 {
204 // class already observed
205 return;
206 }
207 }
208
209 // obtain class reflection
210 $reflection = new ReflectionClass($observer);
211
212 // retrieve all methods
213 $methods = $reflection->getMethods();
214
215 // retrieve all JEvent methods
216 $default = get_class_methods('JEvent');
217
218 foreach ($methods as $method)
219 {
220 // make sure the method is not already used by the parent class,
221 // it is public and it is not static
222 if (!in_array($method->name, $default) && $method->isPublic() && !$method->isStatic())
223 {
224 // get method parameters
225 $params = $method->getParameters();
226
227 /**
228 * Refactor event name at runtime to support the
229 * WordPress hooks notation.
230 *
231 * @since 10.1.32
232 */
233 $hook = $this->getHook($method->name);
234
235 // Register filter.
236 // Always increase parameters counter by one in order to
237 // accept the return value, which is never passed on Joomla.
238 add_filter($hook, array($observer, $method->name), 10, count($params) + 1);
239 }
240 }
241 }
242
243 // cache observer to avoid registering the same events more than once
244 $this->observers[] = $observer;
245 }
246
247 /**
248 * Checks whether the specified event uses the Joomla notation.
249 * In that case, rebuild the event to look more similar to
250 * WordPress hooks.
251 *
252 * @param string $event The event to check.
253 *
254 * @return string The modified event, if needed.
255 *
256 * @since 10.1.32
257 */
258 protected function getHook($event)
259 {
260 // make sure it starts with "on"
261 if (preg_match("/^on[A-Z]/", $event))
262 {
263 // remove initial "on"
264 $event = preg_replace("/^on/", '', $event);
265
266 // recover option from request
267 $option = JFactory::getApplication()->input->get('option');
268
269 if ($option)
270 {
271 // clean "com_" from option
272 $option = preg_replace("/^com_/", '', $option);
273 // remove plugin name from event
274 $event = preg_replace("/{$option}/i", '', $event);
275 // always prepend plugin name at the beginning
276 $event = strtolower($option) . $event;
277 }
278
279 // place an underscore between each camelCase
280 $event = strtolower(preg_replace("/([a-z])([A-Z])/", '$1_$2', $event));
281 }
282
283 return $event;
284 }
285 }
286