4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\EventDispatcher;
15 * The EventDispatcherInterface is the central point of Symfony's event listener system.
17 * Listeners are registered on the manager and events are dispatched through the
20 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21 * @author Jonathan Wage <jonwage@gmail.com>
22 * @author Roman Borschel <roman@code-factory.org>
23 * @author Bernhard Schussek <bschussek@gmail.com>
24 * @author Fabien Potencier <fabien@symfony.com>
25 * @author Jordi Boggiano <j.boggiano@seld.be>
26 * @author Jordan Alliot <jordan.alliot@gmail.com>
27 * @author Nicolas Grekas <p@tchwork.com>
29 class EventDispatcher implements EventDispatcherInterface
31 private $listeners = array();
32 private $sorted = array();
37 public function dispatch($eventName, Event $event = null)
39 if (null === $event) {
43 if ($listeners = $this->getListeners($eventName)) {
44 $this->doDispatch($listeners, $eventName, $event);
53 public function getListeners($eventName = null)
55 if (null !== $eventName) {
56 if (empty($this->listeners[$eventName])) {
60 if (!isset($this->sorted[$eventName])) {
61 $this->sortListeners($eventName);
64 return $this->sorted[$eventName];
67 foreach ($this->listeners as $eventName => $eventListeners) {
68 if (!isset($this->sorted[$eventName])) {
69 $this->sortListeners($eventName);
73 return array_filter($this->sorted);
79 public function getListenerPriority($eventName, $listener)
81 if (empty($this->listeners[$eventName])) {
85 if (is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
86 $listener[0] = $listener[0]();
89 foreach ($this->listeners[$eventName] as $priority => $listeners) {
90 foreach ($listeners as $k => $v) {
91 if ($v !== $listener && is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
93 $this->listeners[$eventName][$priority][$k] = $v;
95 if ($v === $listener) {
105 public function hasListeners($eventName = null)
107 if (null !== $eventName) {
108 return !empty($this->listeners[$eventName]);
111 foreach ($this->listeners as $eventListeners) {
112 if ($eventListeners) {
123 public function addListener($eventName, $listener, $priority = 0)
125 $this->listeners[$eventName][$priority][] = $listener;
126 unset($this->sorted[$eventName]);
132 public function removeListener($eventName, $listener)
134 if (empty($this->listeners[$eventName])) {
138 if (is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
139 $listener[0] = $listener[0]();
142 foreach ($this->listeners[$eventName] as $priority => $listeners) {
143 foreach ($listeners as $k => $v) {
144 if ($v !== $listener && is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
147 if ($v === $listener) {
148 unset($listeners[$k], $this->sorted[$eventName]);
155 $this->listeners[$eventName][$priority] = $listeners;
157 unset($this->listeners[$eventName][$priority]);
165 public function addSubscriber(EventSubscriberInterface $subscriber)
167 foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
168 if (is_string($params)) {
169 $this->addListener($eventName, array($subscriber, $params));
170 } elseif (is_string($params[0])) {
171 $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
173 foreach ($params as $listener) {
174 $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
183 public function removeSubscriber(EventSubscriberInterface $subscriber)
185 foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
186 if (is_array($params) && is_array($params[0])) {
187 foreach ($params as $listener) {
188 $this->removeListener($eventName, array($subscriber, $listener[0]));
191 $this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0]));
197 * Triggers the listeners of an event.
199 * This method can be overridden to add functionality that is executed
202 * @param callable[] $listeners The event listeners
203 * @param string $eventName The name of the event to dispatch
204 * @param Event $event The event object to pass to the event handlers/listeners
206 protected function doDispatch($listeners, $eventName, Event $event)
208 foreach ($listeners as $listener) {
209 if ($event->isPropagationStopped()) {
212 \call_user_func($listener, $event, $eventName, $this);
217 * Sorts the internal list of listeners for the given event by priority.
219 * @param string $eventName The name of the event
221 private function sortListeners($eventName)
223 krsort($this->listeners[$eventName]);
224 $this->sorted[$eventName] = array();
226 foreach ($this->listeners[$eventName] as $priority => $listeners) {
227 foreach ($listeners as $k => $listener) {
228 if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
229 $listener[0] = $listener[0]();
230 $this->listeners[$eventName][$priority][$k] = $listener;
232 $this->sorted[$eventName][] = $listener;