EventDispatcher.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. namespace Symfony\Framework\Debug;
  3. use Symfony\Framework\EventDispatcher as BaseEventDispatcher;
  4. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  5. use Symfony\Component\EventDispatcher\Event;
  6. use Symfony\Component\HttpKernel\Log\LoggerInterface;
  7. /*
  8. * This file is part of the Symfony package.
  9. *
  10. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  11. *
  12. * For the full copyright and license information, please view the LICENSE
  13. * file that was distributed with this source code.
  14. */
  15. /**
  16. * EventDispatcher extends the original EventDispatcher class to add some debugging tools.
  17. *
  18. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  19. */
  20. class EventDispatcher extends BaseEventDispatcher implements EventDispatcherTraceableInterface
  21. {
  22. protected $logger;
  23. protected $called;
  24. /**
  25. * Constructor.
  26. *
  27. * @param LoggerInterface $logger A LoggerInterface instance
  28. */
  29. public function __construct(LoggerInterface $logger = null)
  30. {
  31. $this->logger = $logger;
  32. $this->called = array();
  33. }
  34. /**
  35. * Notifies all listeners of a given event.
  36. *
  37. * @param Event $event A Event instance
  38. *
  39. * @return Event The Event instance
  40. */
  41. public function notify(Event $event)
  42. {
  43. foreach ($this->getListeners($event->getName()) as $listener) {
  44. $this->addCall($event, $listener, 'notify');
  45. call_user_func($listener, $event);
  46. }
  47. return $event;
  48. }
  49. /**
  50. * Notifies all listeners of a given event until one returns a non null value.
  51. *
  52. * @param Event $event A Event instance
  53. *
  54. * @return Event The Event instance
  55. */
  56. public function notifyUntil(Event $event)
  57. {
  58. foreach ($this->getListeners($event->getName()) as $i => $listener) {
  59. $this->addCall($event, $listener, 'notifyUntil');
  60. if (call_user_func($listener, $event)) {
  61. if (null !== $this->logger) {
  62. $this->logger->debug(sprintf('Listener "%s" processed the event "%s"', $this->listenerToString($listener), $event->getName()));
  63. $listeners = $this->getListeners($event->getName());
  64. while (++$i < count($listeners)) {
  65. $this->logger->debug(sprintf('Listener "%s" was not called for event "%s"', $this->listenerToString($listeners[$i]), $event->getName()));
  66. }
  67. }
  68. $event->setProcessed(true);
  69. break;
  70. }
  71. }
  72. return $event;
  73. }
  74. /**
  75. * Filters a value by calling all listeners of a given event.
  76. *
  77. * @param Event $event A Event instance
  78. * @param mixed $value The value to be filtered
  79. *
  80. * @return Event The Event instance
  81. */
  82. public function filter(Event $event, $value)
  83. {
  84. foreach ($this->getListeners($event->getName()) as $listener) {
  85. $this->addCall($event, $listener, 'filter');
  86. $value = call_user_func($listener, $event, $value);
  87. }
  88. $event->setReturnValue($value);
  89. return $event;
  90. }
  91. public function getCalledEvents()
  92. {
  93. return $this->called;
  94. }
  95. public function getNotCalledEvents()
  96. {
  97. $notCalled = array();
  98. foreach (array_keys($this->listeners) as $name) {
  99. foreach ($this->getListeners($name) as $listener) {
  100. $listener = $this->listenerToString($listener);
  101. if (!isset($this->called[$name.'.'.$listener])) {
  102. $notCalled[] = array(
  103. 'event' => $name,
  104. 'listener' => $listener,
  105. );
  106. }
  107. }
  108. }
  109. return $notCalled;
  110. }
  111. protected function listenerToString($listener)
  112. {
  113. if (is_object($listener) && $listener instanceof \Closure) {
  114. return 'Closure';
  115. }
  116. if (is_string($listener)) {
  117. return $listener;
  118. }
  119. if (is_array($listener)) {
  120. return sprintf('%s::%s', is_object($listener[0]) ? get_class($listener[0]) : $listener[0], $listener[1]);
  121. }
  122. }
  123. protected function addCall(Event $event, $listener, $type)
  124. {
  125. $listener = $this->listenerToString($listener);
  126. if (null !== $this->logger) {
  127. $this->logger->debug(sprintf('Notified event "%s" to listener "%s" (%s)', $event->getName(), $listener, $type));
  128. }
  129. $this->called[$event->getName().'.'.$listener] = array(
  130. 'event' => $event->getName(),
  131. 'caller' => null !== $event->getSubject() ? get_class($event->getSubject()) : null,
  132. 'listener' => $listener,
  133. );
  134. }
  135. }