Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of the Symfony package.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Symfony\Component\EventDispatcher;
|
Chris@0
|
13
|
Chris@0
|
14 /**
|
Chris@0
|
15 * The EventDispatcherInterface is the central point of Symfony's event listener system.
|
Chris@0
|
16 *
|
Chris@0
|
17 * Listeners are registered on the manager and events are dispatched through the
|
Chris@0
|
18 * manager.
|
Chris@0
|
19 *
|
Chris@0
|
20 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
Chris@0
|
21 * @author Jonathan Wage <jonwage@gmail.com>
|
Chris@0
|
22 * @author Roman Borschel <roman@code-factory.org>
|
Chris@0
|
23 * @author Bernhard Schussek <bschussek@gmail.com>
|
Chris@0
|
24 * @author Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
25 * @author Jordi Boggiano <j.boggiano@seld.be>
|
Chris@0
|
26 * @author Jordan Alliot <jordan.alliot@gmail.com>
|
Chris@14
|
27 * @author Nicolas Grekas <p@tchwork.com>
|
Chris@0
|
28 */
|
Chris@0
|
29 class EventDispatcher implements EventDispatcherInterface
|
Chris@0
|
30 {
|
Chris@17
|
31 private $listeners = [];
|
Chris@17
|
32 private $sorted = [];
|
Chris@0
|
33
|
Chris@0
|
34 /**
|
Chris@0
|
35 * {@inheritdoc}
|
Chris@0
|
36 */
|
Chris@0
|
37 public function dispatch($eventName, Event $event = null)
|
Chris@0
|
38 {
|
Chris@0
|
39 if (null === $event) {
|
Chris@0
|
40 $event = new Event();
|
Chris@0
|
41 }
|
Chris@0
|
42
|
Chris@0
|
43 if ($listeners = $this->getListeners($eventName)) {
|
Chris@0
|
44 $this->doDispatch($listeners, $eventName, $event);
|
Chris@0
|
45 }
|
Chris@0
|
46
|
Chris@0
|
47 return $event;
|
Chris@0
|
48 }
|
Chris@0
|
49
|
Chris@0
|
50 /**
|
Chris@0
|
51 * {@inheritdoc}
|
Chris@0
|
52 */
|
Chris@0
|
53 public function getListeners($eventName = null)
|
Chris@0
|
54 {
|
Chris@0
|
55 if (null !== $eventName) {
|
Chris@14
|
56 if (empty($this->listeners[$eventName])) {
|
Chris@17
|
57 return [];
|
Chris@0
|
58 }
|
Chris@0
|
59
|
Chris@0
|
60 if (!isset($this->sorted[$eventName])) {
|
Chris@0
|
61 $this->sortListeners($eventName);
|
Chris@0
|
62 }
|
Chris@0
|
63
|
Chris@0
|
64 return $this->sorted[$eventName];
|
Chris@0
|
65 }
|
Chris@0
|
66
|
Chris@0
|
67 foreach ($this->listeners as $eventName => $eventListeners) {
|
Chris@0
|
68 if (!isset($this->sorted[$eventName])) {
|
Chris@0
|
69 $this->sortListeners($eventName);
|
Chris@0
|
70 }
|
Chris@0
|
71 }
|
Chris@0
|
72
|
Chris@0
|
73 return array_filter($this->sorted);
|
Chris@0
|
74 }
|
Chris@0
|
75
|
Chris@0
|
76 /**
|
Chris@0
|
77 * {@inheritdoc}
|
Chris@0
|
78 */
|
Chris@0
|
79 public function getListenerPriority($eventName, $listener)
|
Chris@0
|
80 {
|
Chris@14
|
81 if (empty($this->listeners[$eventName])) {
|
Chris@0
|
82 return;
|
Chris@0
|
83 }
|
Chris@0
|
84
|
Chris@17
|
85 if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
|
Chris@14
|
86 $listener[0] = $listener[0]();
|
Chris@14
|
87 }
|
Chris@14
|
88
|
Chris@0
|
89 foreach ($this->listeners[$eventName] as $priority => $listeners) {
|
Chris@14
|
90 foreach ($listeners as $k => $v) {
|
Chris@17
|
91 if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
|
Chris@14
|
92 $v[0] = $v[0]();
|
Chris@14
|
93 $this->listeners[$eventName][$priority][$k] = $v;
|
Chris@14
|
94 }
|
Chris@14
|
95 if ($v === $listener) {
|
Chris@14
|
96 return $priority;
|
Chris@14
|
97 }
|
Chris@0
|
98 }
|
Chris@0
|
99 }
|
Chris@0
|
100 }
|
Chris@0
|
101
|
Chris@0
|
102 /**
|
Chris@0
|
103 * {@inheritdoc}
|
Chris@0
|
104 */
|
Chris@0
|
105 public function hasListeners($eventName = null)
|
Chris@0
|
106 {
|
Chris@14
|
107 if (null !== $eventName) {
|
Chris@14
|
108 return !empty($this->listeners[$eventName]);
|
Chris@14
|
109 }
|
Chris@14
|
110
|
Chris@14
|
111 foreach ($this->listeners as $eventListeners) {
|
Chris@14
|
112 if ($eventListeners) {
|
Chris@14
|
113 return true;
|
Chris@14
|
114 }
|
Chris@14
|
115 }
|
Chris@14
|
116
|
Chris@14
|
117 return false;
|
Chris@0
|
118 }
|
Chris@0
|
119
|
Chris@0
|
120 /**
|
Chris@0
|
121 * {@inheritdoc}
|
Chris@0
|
122 */
|
Chris@0
|
123 public function addListener($eventName, $listener, $priority = 0)
|
Chris@0
|
124 {
|
Chris@0
|
125 $this->listeners[$eventName][$priority][] = $listener;
|
Chris@0
|
126 unset($this->sorted[$eventName]);
|
Chris@0
|
127 }
|
Chris@0
|
128
|
Chris@0
|
129 /**
|
Chris@0
|
130 * {@inheritdoc}
|
Chris@0
|
131 */
|
Chris@0
|
132 public function removeListener($eventName, $listener)
|
Chris@0
|
133 {
|
Chris@14
|
134 if (empty($this->listeners[$eventName])) {
|
Chris@0
|
135 return;
|
Chris@0
|
136 }
|
Chris@0
|
137
|
Chris@17
|
138 if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
|
Chris@14
|
139 $listener[0] = $listener[0]();
|
Chris@14
|
140 }
|
Chris@14
|
141
|
Chris@0
|
142 foreach ($this->listeners[$eventName] as $priority => $listeners) {
|
Chris@14
|
143 foreach ($listeners as $k => $v) {
|
Chris@17
|
144 if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
|
Chris@14
|
145 $v[0] = $v[0]();
|
Chris@14
|
146 }
|
Chris@14
|
147 if ($v === $listener) {
|
Chris@14
|
148 unset($listeners[$k], $this->sorted[$eventName]);
|
Chris@14
|
149 } else {
|
Chris@14
|
150 $listeners[$k] = $v;
|
Chris@14
|
151 }
|
Chris@14
|
152 }
|
Chris@14
|
153
|
Chris@14
|
154 if ($listeners) {
|
Chris@14
|
155 $this->listeners[$eventName][$priority] = $listeners;
|
Chris@14
|
156 } else {
|
Chris@14
|
157 unset($this->listeners[$eventName][$priority]);
|
Chris@0
|
158 }
|
Chris@0
|
159 }
|
Chris@0
|
160 }
|
Chris@0
|
161
|
Chris@0
|
162 /**
|
Chris@0
|
163 * {@inheritdoc}
|
Chris@0
|
164 */
|
Chris@0
|
165 public function addSubscriber(EventSubscriberInterface $subscriber)
|
Chris@0
|
166 {
|
Chris@0
|
167 foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
|
Chris@17
|
168 if (\is_string($params)) {
|
Chris@17
|
169 $this->addListener($eventName, [$subscriber, $params]);
|
Chris@17
|
170 } elseif (\is_string($params[0])) {
|
Chris@17
|
171 $this->addListener($eventName, [$subscriber, $params[0]], isset($params[1]) ? $params[1] : 0);
|
Chris@0
|
172 } else {
|
Chris@0
|
173 foreach ($params as $listener) {
|
Chris@17
|
174 $this->addListener($eventName, [$subscriber, $listener[0]], isset($listener[1]) ? $listener[1] : 0);
|
Chris@0
|
175 }
|
Chris@0
|
176 }
|
Chris@0
|
177 }
|
Chris@0
|
178 }
|
Chris@0
|
179
|
Chris@0
|
180 /**
|
Chris@0
|
181 * {@inheritdoc}
|
Chris@0
|
182 */
|
Chris@0
|
183 public function removeSubscriber(EventSubscriberInterface $subscriber)
|
Chris@0
|
184 {
|
Chris@0
|
185 foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
|
Chris@17
|
186 if (\is_array($params) && \is_array($params[0])) {
|
Chris@0
|
187 foreach ($params as $listener) {
|
Chris@17
|
188 $this->removeListener($eventName, [$subscriber, $listener[0]]);
|
Chris@0
|
189 }
|
Chris@0
|
190 } else {
|
Chris@17
|
191 $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]);
|
Chris@0
|
192 }
|
Chris@0
|
193 }
|
Chris@0
|
194 }
|
Chris@0
|
195
|
Chris@0
|
196 /**
|
Chris@0
|
197 * Triggers the listeners of an event.
|
Chris@0
|
198 *
|
Chris@0
|
199 * This method can be overridden to add functionality that is executed
|
Chris@0
|
200 * for each listener.
|
Chris@0
|
201 *
|
Chris@0
|
202 * @param callable[] $listeners The event listeners
|
Chris@0
|
203 * @param string $eventName The name of the event to dispatch
|
Chris@0
|
204 * @param Event $event The event object to pass to the event handlers/listeners
|
Chris@0
|
205 */
|
Chris@0
|
206 protected function doDispatch($listeners, $eventName, Event $event)
|
Chris@0
|
207 {
|
Chris@0
|
208 foreach ($listeners as $listener) {
|
Chris@0
|
209 if ($event->isPropagationStopped()) {
|
Chris@0
|
210 break;
|
Chris@0
|
211 }
|
Chris@14
|
212 \call_user_func($listener, $event, $eventName, $this);
|
Chris@0
|
213 }
|
Chris@0
|
214 }
|
Chris@0
|
215
|
Chris@0
|
216 /**
|
Chris@0
|
217 * Sorts the internal list of listeners for the given event by priority.
|
Chris@0
|
218 *
|
Chris@0
|
219 * @param string $eventName The name of the event
|
Chris@0
|
220 */
|
Chris@0
|
221 private function sortListeners($eventName)
|
Chris@0
|
222 {
|
Chris@0
|
223 krsort($this->listeners[$eventName]);
|
Chris@17
|
224 $this->sorted[$eventName] = [];
|
Chris@14
|
225
|
Chris@14
|
226 foreach ($this->listeners[$eventName] as $priority => $listeners) {
|
Chris@14
|
227 foreach ($listeners as $k => $listener) {
|
Chris@14
|
228 if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
|
Chris@14
|
229 $listener[0] = $listener[0]();
|
Chris@14
|
230 $this->listeners[$eventName][$priority][$k] = $listener;
|
Chris@14
|
231 }
|
Chris@14
|
232 $this->sorted[$eventName][] = $listener;
|
Chris@14
|
233 }
|
Chris@14
|
234 }
|
Chris@0
|
235 }
|
Chris@0
|
236 }
|