123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- <?php
- namespace Drupal\webprofiler\EventDispatcher;
- use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
- use Drupal\webprofiler\Stopwatch;
- use Symfony\Component\DependencyInjection\ContainerInterface;
- use Symfony\Component\EventDispatcher\Event;
- use Symfony\Component\HttpKernel\KernelEvents;
- /**
- * Class TraceableEventDispatcher
- */
- class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements EventDispatcherTraceableInterface {
- /**
- * @var \Drupal\webprofiler\Stopwatch
- * The stopwatch service.
- */
- protected $stopwatch;
- /**
- * @var array
- */
- protected $calledListeners;
- /**
- * @var array
- */
- protected $notCalledListeners;
- /**
- * {@inheritdoc}
- */
- public function __construct(ContainerInterface $container, array $listeners = []) {
- parent::__construct($container, $listeners);
- $this->notCalledListeners = $listeners;
- }
- /**
- * {@inheritdoc}
- */
- public function addListener($event_name, $listener, $priority = 0) {
- parent::addListener($event_name, $listener, $priority);
- $this->notCalledListeners[$event_name][$priority][] = ['callable' => $listener];
- }
- /**
- * {@inheritdoc}
- */
- public function dispatch($event_name, Event $event = NULL) {
- if ($event === NULL) {
- $event = new Event();
- }
- $this->preDispatch($event_name, $event);
- $e = $this->stopwatch->start($event_name, 'section');
- if (isset($this->listeners[$event_name])) {
- // Sort listeners if necessary.
- if (isset($this->unsorted[$event_name])) {
- krsort($this->listeners[$event_name]);
- unset($this->unsorted[$event_name]);
- }
- // Invoke listeners and resolve callables if necessary.
- foreach ($this->listeners[$event_name] as $priority => &$definitions) {
- foreach ($definitions as $key => &$definition) {
- if (!isset($definition['callable'])) {
- $definition['callable'] = [
- $this->container->get($definition['service'][0]),
- $definition['service'][1],
- ];
- }
- $definition['callable']($event, $event_name, $this);
- $this->addCalledListener($definition, $event_name, $priority);
- if ($event->isPropagationStopped()) {
- return $event;
- }
- }
- }
- }
- if ($e->isStarted()) {
- $e->stop();
- }
- $this->postDispatch($event_name, $event);
- return $event;
- }
- /**
- * {@inheritdoc}
- */
- public function getCalledListeners() {
- return $this->calledListeners;
- }
- /**
- * {@inheritdoc}
- */
- public function getNotCalledListeners() {
- return $this->notCalledListeners;
- }
- /**
- * @param \Drupal\webprofiler\Stopwatch $stopwatch
- */
- public function setStopwatch(Stopwatch $stopwatch) {
- $this->stopwatch = $stopwatch;
- }
- /**
- * Called before dispatching the event.
- *
- * @param string $eventName The event name
- * @param Event $event The event
- */
- protected function preDispatch($eventName, Event $event) {
- switch ($eventName) {
- case KernelEvents::VIEW:
- case KernelEvents::RESPONSE:
- // stop only if a controller has been executed
- if ($this->stopwatch->isStarted('controller')) {
- $this->stopwatch->stop('controller');
- }
- break;
- }
- }
- /**
- * Called after dispatching the event.
- *
- * @param string $eventName The event name
- * @param Event $event The event
- */
- protected function postDispatch($eventName, Event $event) {
- switch ($eventName) {
- case KernelEvents::CONTROLLER:
- $this->stopwatch->start('controller', 'section');
- break;
- case KernelEvents::RESPONSE:
- $token = $event->getResponse()->headers->get('X-Debug-Token');
- try {
- $this->stopwatch->stopSection($token);
- }
- catch (\LogicException $e) {
- }
- break;
- case KernelEvents::TERMINATE:
- // In the special case described in the `preDispatch` method above, the `$token` section
- // does not exist, then closing it throws an exception which must be caught.
- $token = $event->getResponse()->headers->get('X-Debug-Token');
- try {
- $this->stopwatch->stopSection($token);
- }
- catch (\LogicException $e) {
- }
- break;
- }
- }
- /**
- * @param $definition
- * @param $event_name
- * @param $priority
- */
- private function addCalledListener($definition, $event_name, $priority) {
- if ($this->isClosure($definition['callable'])) {
- $this->calledListeners[$event_name][$priority][] = [
- 'class' => 'Closure',
- 'method' => '',
- ];
- }
- else {
- $this->calledListeners[$event_name][$priority][] = [
- 'class' => get_class($definition['callable'][0]),
- 'method' => $definition['callable'][1],
- ];
- }
- foreach ($this->notCalledListeners[$event_name][$priority] as $key => $listener) {
- if (isset($listener['service'])) {
- if ($listener['service'][0] == $definition['service'][0] && $listener['service'][1] == $definition['service'][1]) {
- unset($this->notCalledListeners[$event_name][$priority][$key]);
- }
- }
- else {
- if ($this->isClosure($listener['callable'])) {
- if (is_callable($listener['callable'], TRUE, $listenerCallableName) && is_callable($definition['callable'], TRUE, $definitionCallableName)) {
- if ($listenerCallableName == $definitionCallableName) {
- unset($this->notCalledListeners[$event_name][$priority][$key]);
- }
- }
- }
- else {
- if (get_class($listener['callable'][0]) == get_class($definition['callable'][0]) && $listener['callable'][1] == $definition['callable'][1]) {
- unset($this->notCalledListeners[$event_name][$priority][$key]);
- }
- }
- }
- }
- }
- private function isClosure($t) {
- return is_object($t) && ($t instanceof \Closure);
- }
- }
|