1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PEIP\Dispatcher; |
4
|
|
|
|
5
|
|
|
namespace PEIP\Dispatcher; |
6
|
|
|
|
7
|
|
|
/* |
8
|
|
|
* This file is part of the PEIP package. |
9
|
|
|
* (c) 2009-2016 Timo Michna <timomichna/yahoo.de> |
10
|
|
|
* |
11
|
|
|
* For the full copyright and license information, please view the LICENSE |
12
|
|
|
* file that was distributed with this source code. |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
/* |
16
|
|
|
* ObjectMapDispatcher |
17
|
|
|
* Event dispatcher for an abritrary amount of different objects and events. |
18
|
|
|
* Framework internally this class (and derived classes) are used to reduce the overall |
19
|
|
|
* amount of dispatcher instances. |
20
|
|
|
* |
21
|
|
|
* @author Timo Michna <timomichna/yahoo.de> |
22
|
|
|
* @package PEIP |
23
|
|
|
* @subpackage dispatcher |
24
|
|
|
* @implements \PEIP\INF\Dispatcher\ObjectMapDispatcher |
25
|
|
|
*/ |
26
|
|
|
|
27
|
|
|
use PEIP\Base\ObjectStorage; |
28
|
|
|
use PEIP\Util\Test; |
29
|
|
|
|
30
|
|
|
class ObjectMapDispatcher implements \PEIP\INF\Dispatcher\ObjectMapDispatcher |
31
|
|
|
{ |
32
|
|
|
protected $listeners = null, |
33
|
|
|
$classDispatcher = null; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* connects a Handler to an event on an object. |
37
|
|
|
* |
38
|
|
|
* @param string $name the event-name |
39
|
|
|
* @param object $object arbitrary object to connect to |
40
|
|
|
* @param callable|PEIP\INF\Handler\Handler $listener event-handler |
41
|
|
|
* |
42
|
|
|
* @return bool |
43
|
|
|
*/ |
44
|
|
|
public function connect($name, $object, $listener) |
45
|
|
|
{ |
46
|
|
|
Test::ensureHandler($listener); |
47
|
|
|
$listners = $this->doGetListeners(); |
48
|
|
|
if (!$this->listeners->contains($object)) { |
49
|
|
|
$this->listeners->attach($object, new \ArrayObject()); |
50
|
|
|
} |
51
|
|
|
if (!array_key_exists($name, $listners[$object])) { |
52
|
|
|
$this->listeners[$object][$name] = []; |
53
|
|
|
} |
54
|
|
|
$hash = $this->getListenerHash($listener); |
55
|
|
|
$this->listeners[$object][$name][$hash] = $listener; |
56
|
|
|
|
57
|
|
|
return true; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Disconnects a Handler from an event on an object. |
62
|
|
|
* |
63
|
|
|
* @param string $name the event-name |
64
|
|
|
* @param object $object arbitrary object to disconnect from |
65
|
|
|
* @param \PEIP\INF\Handler\Handler $listener event-handler |
66
|
|
|
* |
67
|
|
|
* @return bool |
68
|
|
|
*/ |
69
|
|
|
public function disconnect($name, $object, $listener) |
70
|
|
|
{ |
71
|
|
|
$listners = $this->doGetListeners(); |
72
|
|
|
if (!$listners->contains($object) || !isset($listners[$object][$name])) { |
73
|
|
|
return false; |
74
|
|
|
} |
75
|
|
|
$eventListeners = $listners[$object][$name]; |
76
|
|
|
$hash = $this->getListenerHash($listener); |
77
|
|
|
if (isset($eventListeners[$hash])) { |
78
|
|
|
unset($eventListeners[$hash]); |
79
|
|
|
|
80
|
|
|
$listners[$object][$name] = $eventListeners; |
81
|
|
|
|
82
|
|
|
return true; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
return false; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
public function disconnectAll($name, $object) |
89
|
|
|
{ |
90
|
|
View Code Duplication |
if (is_object($object)) { |
|
|
|
|
91
|
|
|
$listners = $this->doGetListeners(); |
92
|
|
|
if ($listners && $this->hadListeners($name, $object)) { |
93
|
|
|
$listners[$object][$name] = []; |
94
|
|
|
} |
95
|
|
|
} |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Checks wether an object has a listener for an event. |
100
|
|
|
* |
101
|
|
|
* @param string $name the event-name |
102
|
|
|
* @param object $object object to check for listeners |
103
|
|
|
* |
104
|
|
|
* @return bool |
105
|
|
|
*/ |
106
|
|
|
public function hasListeners($name, $object) |
107
|
|
|
{ |
108
|
|
|
$listners = $this->doGetListeners(); |
|
|
|
|
109
|
|
View Code Duplication |
if (!$this->hadListeners($name, $object)) { |
|
|
|
|
110
|
|
|
$res = false; |
111
|
|
|
} else { |
112
|
|
|
$listners = $this->doGetListeners(); |
113
|
|
|
$res = (bool) count($listners[$object][$name]); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
return $res; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Checks wether an object has or had a listener for an event. |
121
|
|
|
* |
122
|
|
|
* @param string $name the event-name |
123
|
|
|
* @param object $object object to check for listeners |
124
|
|
|
* |
125
|
|
|
* @return bool |
126
|
|
|
*/ |
127
|
|
|
public function hadListeners($name, $object) |
128
|
|
|
{ |
129
|
|
|
$listners = $this->doGetListeners(); |
130
|
|
|
|
131
|
|
|
return ($listners->contains($object) && isset($listners[$object][$name])) ? true : false; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Returns all event-names an object has registered listeners for. |
136
|
|
|
* |
137
|
|
|
* @param object $object object to get event-names for |
138
|
|
|
* |
139
|
|
|
* @return string[] array of event-names |
140
|
|
|
*/ |
141
|
|
|
public function getEventNames($object) |
142
|
|
|
{ |
143
|
|
|
$listeners = $this->doGetListeners(); |
144
|
|
|
if (!$listeners->contains($object)) { |
145
|
|
|
return []; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
return array_keys($listeners[$object]->getArrayCopy()); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Notifies all listeners of a given event on an object. |
153
|
|
|
* |
154
|
|
|
* @param $name |
155
|
|
|
* @param $object |
156
|
|
|
* |
157
|
|
|
* @return bool |
158
|
|
|
*/ |
159
|
|
|
public function notify($name, $object) |
160
|
|
|
{ |
161
|
|
|
if ($this->hasListeners($name, $object)) { |
162
|
|
|
$listners = $this->doGetListeners(); |
163
|
|
|
self::doNotify($listners[$object][$name], $object); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
return true; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Notifies all listeners of a given event on an object |
171
|
|
|
* until one returns a non null value. |
172
|
|
|
* |
173
|
|
|
* @param $name |
174
|
|
|
* @param $subject |
175
|
|
|
* |
176
|
|
|
* @return \PEIP\INF\Handler\Handler |
177
|
|
|
*/ |
178
|
|
|
public function notifyUntil($name, $subject) |
179
|
|
|
{ |
180
|
|
|
if ($this->hasListeners($name, $subject)) { |
181
|
|
|
$res = self::doNotifyUntil($this->getListeners($name, $subject), $subject); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
return $res; |
|
|
|
|
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Returns all listeners of a given event on an object. |
189
|
|
|
* |
190
|
|
|
* @param string $name the event-name |
191
|
|
|
* @param object $object object to check for listeners |
192
|
|
|
* |
193
|
|
|
* @return array array of listeners |
194
|
|
|
*/ |
195
|
|
|
public function getListeners($name, $object) |
196
|
|
|
{ |
197
|
|
|
if (!$this->hadListeners($name, $object)) { |
198
|
|
|
return []; |
199
|
|
|
} |
200
|
|
|
$listeners = $this->listeners[$object]->getArrayCopy(); |
201
|
|
|
|
202
|
|
|
return array_values($listeners[$name]); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Returns ObjectStorage object to store objects to lositen to in. |
207
|
|
|
* creates ObjectStorage if not exists. |
208
|
|
|
* |
209
|
|
|
* @return ObjectStorage |
210
|
|
|
*/ |
211
|
|
|
protected function doGetListeners() |
212
|
|
|
{ |
213
|
|
|
return isset($this->listeners) ? $this->listeners : $this->listeners = new ObjectStorage(); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Notifies all given listeners about an subject. |
218
|
|
|
* |
219
|
|
|
* @static |
220
|
|
|
* |
221
|
|
|
* @param $name |
222
|
|
|
* @param $object |
223
|
|
|
* |
224
|
|
|
* @return bool|null |
225
|
|
|
*/ |
226
|
|
|
protected static function doNotify(array $listeners, $subject) |
227
|
|
|
{ |
228
|
|
|
foreach ($listeners as $listener) { |
229
|
|
|
if ($listener instanceof \PEIP\INF\Handler\Handler) { |
230
|
|
|
$listener->handle($subject); |
231
|
|
|
} elseif (is_callable($listener)) { |
232
|
|
|
call_user_func($listener, $subject); |
233
|
|
|
} |
234
|
|
|
} |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* Notifies all given listeners about an subject untill one returns a boolean true value. |
239
|
|
|
* |
240
|
|
|
* @static |
241
|
|
|
* |
242
|
|
|
* @param $name |
243
|
|
|
* @param $object |
244
|
|
|
* |
245
|
|
|
* @return \PEIP\INF\Handler\Handler the listener which returned a boolean true value |
246
|
|
|
*/ |
247
|
|
|
protected static function doNotifyUntil(array $listeners, $subject) |
248
|
|
|
{ |
249
|
|
|
$res = null; |
250
|
|
|
foreach ($listeners as $listener) { |
251
|
|
|
if ($listener instanceof \PEIP\INF\Handler\Handler) { |
252
|
|
|
$res = $listener->handle($subject); |
253
|
|
|
if ($res) { |
254
|
|
|
return $listener; |
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
return $res; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
protected function getListenerHash($listener) |
263
|
|
|
{ |
264
|
|
|
if (!is_object($listener)) { |
265
|
|
|
$o = new \stdClass(); |
266
|
|
|
$o->listener = $listener; |
267
|
|
|
$listener = $o; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
return spl_object_hash($listener); |
271
|
|
|
} |
272
|
|
|
} |
273
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.