View source
<?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 extends ContainerAwareEventDispatcher implements EventDispatcherTraceableInterface {
protected $stopwatch;
protected $calledListeners;
protected $notCalledListeners;
public function __construct(ContainerInterface $container, array $listeners = []) {
parent::__construct($container, $listeners);
$this->notCalledListeners = $listeners;
}
public function addListener($event_name, $listener, $priority = 0) {
parent::addListener($event_name, $listener, $priority);
$this->notCalledListeners[$event_name][$priority][] = [
'callable' => $listener,
];
}
public function dispatch($event, $event_name = NULL) {
if (is_string($event)) {
$event_obj = $event_name ?? new Event();
$event_name = $event;
$event = $event_obj;
}
$this
->preDispatch($event_name, $event);
$e = $this->stopwatch
->start($event_name, 'section');
if (isset($this->listeners[$event_name])) {
if (isset($this->unsorted[$event_name])) {
krsort($this->listeners[$event_name]);
unset($this->unsorted[$event_name]);
}
foreach ($this->listeners[$event_name] as $priority => &$definitions) {
foreach ($definitions as &$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;
}
public function getCalledListeners() {
return $this->calledListeners;
}
public function getNotCalledListeners() {
return $this->notCalledListeners;
}
public function setStopwatch(Stopwatch $stopwatch) {
$this->stopwatch = $stopwatch;
}
protected function preDispatch($eventName, Event $event) {
switch ($eventName) {
case KernelEvents::VIEW:
case KernelEvents::RESPONSE:
if ($this->stopwatch
->isStarted('controller')) {
$this->stopwatch
->stop('controller');
}
break;
}
}
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:
$token = $event
->getResponse()->headers
->get('X-Debug-Token');
try {
$this->stopwatch
->stopSection($token);
} catch (\LogicException $e) {
}
break;
}
}
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;
}
}