Skip to content
Snippets Groups Projects

Fix issues with D11

Merged Luca Lusso requested to merge d11 into 1.1.x
Files
4
@@ -4,23 +4,16 @@ declare(strict_types=1);
namespace Drupal\tracer\EventDispatcher;
use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
use Drupal\tracer\TracerInterface;
use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Extends the Symfony event dispatcher to trace events.
* Decorates the Symfony event dispatcher to trace events.
*/
class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements EventDispatcherTraceableInterface {
/**
* The Tracer instance.
*
* @var \Drupal\tracer\TracerInterface
*/
protected TracerInterface $tracer;
class TraceableEventDispatcher implements EventDispatcherTraceableInterface {
/**
* An array of all the events that have been dispatched.
@@ -44,69 +37,41 @@ class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements
private ?object $controllerSpan;
/**
* {@inheritdoc}
* Constructs a traceable event dispatcher.
*
* @param \Drupal\tracer\TracerInterface $tracer
* The Tracer instance.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $inner
* The decorated event_dispatcher service.
*/
public function __construct(
ContainerInterface $container,
array $listeners = [],
protected TracerInterface $tracer,
protected EventDispatcherInterface $inner,
) {
parent::__construct($container, $listeners);
$this->notCalledListeners = $listeners;
$this->controllerSpan = NULL;
}
/**
* {@inheritdoc}
*/
public function addListener($event_name, $listener, $priority = 0) {
parent::addListener($event_name, $listener, $priority);
public function addListener($eventName, $listener, $priority = 0): void {
$this->inner->addListener($eventName, $listener, $priority);
$this->notCalledListeners[$event_name][$priority][] = ['callable' => $listener];
$this->notCalledListeners[$eventName][$priority][] = ['callable' => $listener];
}
/**
* Trace the start and stop of the event processing.
*/
public function dispatch(object $event, ?string $eventName = NULL): object {
$event_name = $eventName ?? \get_class($event);
$eventName = $eventName ?? \get_class($event);
$this->beforeDispatch($event_name, $event);
$this->beforeDispatch($eventName, $event);
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 &$definition) {
if (!isset($definition['callable'])) {
$definition['callable'] = [
$this->container->get($definition['service'][0]),
$definition['service'][1],
];
}
if (\is_array($definition['callable']) && isset($definition['callable'][0]) && $definition['callable'][0] instanceof \Closure) {
$definition['callable'][0] = $definition['callable'][0]();
}
$span = $this->tracer->start('event', $event_name, ['priority' => $priority]);
\call_user_func($definition['callable'], $event, $event_name, $this);
$this->tracer->stop($span);
$this->addCalledListener($definition, $event_name, $priority);
if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
return $event;
}
}
}
}
$listeners = $this->getListeners($eventName);
$this->callListeners($listeners, $eventName, $event);
$this->afterDispatch($event_name, $event);
$this->afterDispatch($eventName, $event);
return $event;
}
@@ -125,16 +90,6 @@ class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements
return $this->notCalledListeners;
}
/**
* Set the Tracer instance.
*
* @param \Drupal\tracer\TracerInterface $tracer
* The Tracer's instance.
*/
public function setTracer(TracerInterface $tracer): void {
$this->tracer = $tracer;
}
/**
* Called before dispatching the event.
*
@@ -169,68 +124,113 @@ class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements
}
}
/**
* Triggers the listeners of an event.
*
* This method can be overridden to add functionality that is executed
* for each listener.
*
* @param callable[] $listeners
* The event listeners.
* @param string $eventName
* The name of the event to dispatch.
* @param object $event
* The event object to pass to the event handlers/listeners.
*/
protected function callListeners(iterable $listeners, string $eventName, object $event): void {
$stoppable = $event instanceof StoppableEventInterface;
foreach ($listeners as $listener) {
if ($stoppable && $event->isPropagationStopped()) {
break;
}
$priority = $this->getListenerPriority($eventName, $listener);
$span = $this->tracer->start('event', $eventName, ['priority' => $priority]);
$listener($event, $eventName, $this);
$this->tracer->stop($span);
$this->addCalledListener($listener, $eventName, $priority);
}
}
/**
* Add listener to the called listeners array.
*
* @param array $definition
* The event's definition.
* @param array $callable
* The event's callable.
* @param string $event_name
* The event's name.
* @param int $priority
* The event's priority.
*/
private function addCalledListener(array $definition, string $event_name, int $priority): void {
if ($this->isClosure($definition['callable'])) {
$this->calledListeners[$event_name][$priority][] = [
'class' => 'Closure',
'method' => '',
];
}
else {
$class = \is_string($definition['callable'][0]) ? $definition['callable'][0] : \get_class($definition['callable'][0]);
$this->calledListeners[$event_name][$priority][] = [
'class' => $class,
'method' => $definition['callable'][1],
];
}
private function addCalledListener(array $callable, string $event_name, int $priority): void {
$class = \is_string($callable[0]) ? $callable[0] : \get_class($callable[0]);
$this->calledListeners[$event_name][$priority][] = [
'class' => $class,
'method' => $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]) {
if ($listener['callable'][0] instanceof \Closure) {
$listener['callable'][0] = $listener['callable'][0]();
}
if (\is_callable($listener['callable'], TRUE, $listenerCallableName) && \is_callable($callable, TRUE, $definitionCallableName)) {
if ($listenerCallableName == $definitionCallableName) {
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 {
$listener_class = \is_string($listener['callable'][0]) ? $listener['callable'][0] : \get_class($listener['callable'][0]);
$definition_class = \is_string($definition['callable'][0]) ? $definition['callable'][0] : \get_class($definition['callable'][0]);
if ($listener_class == $definition_class && $listener['callable'][1] == $definition['callable'][1]) {
unset($this->notCalledListeners[$event_name][$priority][$key]);
}
$listener_class = \is_string($listener['callable'][0]) ? $listener['callable'][0] : \get_class($listener['callable'][0]);
$definition_class = \is_string($callable[0]) ? $callable[0] : \get_class($callable[0]);
if ($listener_class == $definition_class && $listener['callable'][1] == $callable[1]) {
unset($this->notCalledListeners[$event_name][$priority][$key]);
}
}
}
}
/**
* Returns whether the given callable is a closure.
*
* @param callable $t
* The callable.
*
* @return bool
* TRUE if the callable is a closure, FALSE otherwise.
* Delegate call to the decorated class.
*/
public function addSubscriber(EventSubscriberInterface $subscriber): void {
$this->inner->addSubscriber($subscriber);
}
/**
* Delegate call to the decorated class.
*/
public function removeListener(string $eventName, callable $listener): void {
$this->inner->removeListener($eventName, $listener);
}
/**
* Delegate call to the decorated class.
*/
public function removeSubscriber(EventSubscriberInterface $subscriber): void {
$this->inner->removeSubscriber($subscriber);
}
/**
* Delegate call to the decorated class.
*/
public function getListeners(?string $eventName = NULL): array {
return $this->inner->getListeners($eventName);
}
/**
* Delegate call to the decorated class.
*/
public function getListenerPriority(string $eventName, callable $listener): ?int {
return $this->inner->getListenerPriority($eventName, $listener);
}
/**
* Delegate call to the decorated class.
*/
private function isClosure(callable $t): bool {
return $t instanceof \Closure;
public function hasListeners(?string $eventName = NULL): bool {
return $this->inner->hasListeners($eventName);
}
}
Loading