EventDispatcher.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the LGPL. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Symfony\Component\EventDispatcher;
  20. /**
  21. * The EventDispatcherInterface is the central point of Symfony's event listener system.
  22. *
  23. * Listeners are registered on the manager and events are dispatched through the
  24. * manager.
  25. *
  26. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  27. * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
  28. * @author Jonathan Wage <jonwage@gmail.com>
  29. * @author Roman Borschel <roman@code-factory.org>
  30. * @author Bernhard Schussek <bschussek@gmail.com>
  31. * @author Fabien Potencier <fabien@symfony.com>
  32. * @author Jordi Boggiano <j.boggiano@seld.be>
  33. *
  34. * @api
  35. */
  36. class EventDispatcher implements EventDispatcherInterface
  37. {
  38. private $listeners = array();
  39. /**
  40. * @see EventDispatcherInterface::dispatch
  41. *
  42. * @api
  43. */
  44. public function dispatch($eventName, Event $event = null)
  45. {
  46. if (!isset($this->listeners[$eventName])) {
  47. return;
  48. }
  49. if (null === $event) {
  50. $event = new Event();
  51. }
  52. $this->doDispatch($this->getListeners($eventName), $eventName, $event);
  53. }
  54. /**
  55. * @see EventDispatcherInterface::getListeners
  56. *
  57. * @api
  58. */
  59. public function getListeners($eventName = null)
  60. {
  61. if (null !== $eventName) {
  62. return $this->sortListeners($eventName);
  63. }
  64. $sorted = array();
  65. foreach (array_keys($this->listeners) as $eventName) {
  66. $sorted[$eventName] = $this->sortListeners($eventName);
  67. }
  68. return $sorted;
  69. }
  70. /**
  71. * @see EventDispatcherInterface::hasListeners
  72. *
  73. * @api
  74. */
  75. public function hasListeners($eventName = null)
  76. {
  77. return (Boolean) count($this->getListeners($eventName));
  78. }
  79. /**
  80. * @see EventDispatcherInterface::addListener
  81. *
  82. * @api
  83. */
  84. public function addListener($eventName, $listener, $priority = 0)
  85. {
  86. if (!isset($this->listeners[$eventName][$priority])) {
  87. if (!isset($this->listeners[$eventName])) {
  88. $this->listeners[$eventName] = array();
  89. }
  90. $this->listeners[$eventName][$priority] = array();
  91. }
  92. $this->listeners[$eventName][$priority][] = $listener;
  93. }
  94. /**
  95. * @see EventDispatcherInterface::removeListener
  96. */
  97. public function removeListener($eventName, $listener)
  98. {
  99. if (!isset($this->listeners[$eventName])) {
  100. return;
  101. }
  102. foreach ($this->listeners[$eventName] as $priority => $listeners) {
  103. if (false !== ($key = array_search($listener, $listeners))) {
  104. unset($this->listeners[$eventName][$priority][$key]);
  105. }
  106. }
  107. }
  108. /**
  109. * @see EventDispatcherInterface::addSubscriber
  110. */
  111. public function addSubscriber(EventSubscriberInterface $subscriber, $priority = 0)
  112. {
  113. foreach ($subscriber->getSubscribedEvents() as $eventName => $method) {
  114. $this->addListener($eventName, array($subscriber, $method), $priority);
  115. }
  116. }
  117. /**
  118. * @see EventDispatcherInterface::removeSubscriber
  119. */
  120. public function removeSubscriber(EventSubscriberInterface $subscriber)
  121. {
  122. foreach ($subscriber->getSubscribedEvents() as $eventName => $method) {
  123. $this->removeListener($eventName, array($subscriber, $method));
  124. }
  125. }
  126. /**
  127. * Triggers the listeners of an event.
  128. *
  129. * This method can be overridden to add functionality that is executed
  130. * for each listener.
  131. *
  132. * @param array[callback] $listeners The event listeners.
  133. * @param string $eventName The name of the event to dispatch.
  134. * @param Event $event The event object to pass to the event handlers/listeners.
  135. */
  136. protected function doDispatch($listeners, $eventName, Event $event)
  137. {
  138. foreach ($listeners as $listener) {
  139. call_user_func($listener, $event);
  140. if ($event->isPropagationStopped()) {
  141. break;
  142. }
  143. }
  144. }
  145. /**
  146. * Sorts the internal list of listeners for the given event by priority.
  147. *
  148. * @param string $eventName The name of the event.
  149. */
  150. private function sortListeners($eventName)
  151. {
  152. if (!isset($this->listeners[$eventName])) {
  153. return array();
  154. }
  155. krsort($this->listeners[$eventName]);
  156. return call_user_func_array('array_merge', $this->listeners[$eventName]);
  157. }
  158. }