TraceableEventDispatcher.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\FrameworkBundle\Debug;
  11. use Symfony\Bundle\FrameworkBundle\ContainerAwareEventDispatcher;
  12. use Symfony\Component\HttpKernel\Log\LoggerInterface;
  13. use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcherInterface;
  14. use Symfony\Component\DependencyInjection\ContainerInterface;
  15. use Symfony\Component\EventDispatcher\Event;
  16. /**
  17. * Extends the ContainerAwareEventDispatcher to add some debugging tools.
  18. *
  19. * @author Fabien Potencier <fabien@symfony.com>
  20. */
  21. class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements TraceableEventDispatcherInterface
  22. {
  23. protected $logger;
  24. protected $called;
  25. /**
  26. * Constructor.
  27. *
  28. * @param ContainerInterface $container A ContainerInterface instance
  29. * @param LoggerInterface $logger A LoggerInterface instance
  30. */
  31. public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
  32. {
  33. parent::__construct($container);
  34. $this->logger = $logger;
  35. $this->called = array();
  36. }
  37. /**
  38. * {@inheritDoc}
  39. */
  40. protected function triggerListener($listener, $eventName, Event $event)
  41. {
  42. parent::triggerListener($listener, $eventName, $event);
  43. $listenerString = $this->listenerToString($listener, $eventName);
  44. if (null !== $this->logger) {
  45. $this->logger->debug(sprintf('Notified event "%s" to listener "%s"', $eventName, $listenerString));
  46. }
  47. $this->called[$eventName.'.'.$listenerString] = array(
  48. 'event' => $eventName,
  49. 'listener' => $listenerString,
  50. );
  51. if ($event->isPropagationStopped() && null !== $this->logger) {
  52. $this->logger->debug(sprintf('Listener "%s" stopped propagation of the event "%s"', $this->listenerToString($listener), $eventName));
  53. $skippedListeners = $this->getListeners($eventName);
  54. $skipped = false;
  55. foreach ($skippedListeners as $skippedListener) {
  56. if ($skipped) {
  57. $this->logger->debug(sprintf('Listener "%s" was not called for event "%s"', $this->listenerToString($skippedListener), $eventName));
  58. }
  59. if ($skippedListener === $listener) {
  60. $skipped = false;
  61. }
  62. }
  63. }
  64. }
  65. /**
  66. * {@inheritDoc}
  67. */
  68. public function getCalledListeners()
  69. {
  70. return $this->called;
  71. }
  72. /**
  73. * {@inheritDoc}
  74. */
  75. public function getNotCalledListeners()
  76. {
  77. $notCalled = array();
  78. foreach (array_keys($this->listeners) as $name) {
  79. foreach ($this->getListeners($name) as $listener) {
  80. $listener = $this->listenerToString($listener);
  81. if (!isset($this->called[$name.'.'.$listener])) {
  82. $notCalled[] = array(
  83. 'event' => $name,
  84. 'listener' => $listener,
  85. );
  86. }
  87. }
  88. }
  89. return $notCalled;
  90. }
  91. protected function listenerToString($listener, $eventName)
  92. {
  93. if (is_object($listener)) {
  94. if ($listener instanceof \Closure) {
  95. return 'Closure';
  96. }
  97. return get_class($listener).'::'.$eventName;
  98. }
  99. if (is_array($listener)) {
  100. return is_object($listener[0]) ? sprintf('%s::%s', get_class($listener[0]), $listener[1]) : implode('::', $listener);
  101. }
  102. }
  103. }