[EventDispatcher] Split events across requests
This commit is contained in:
parent
aa5b6f95b9
commit
c3477badbc
@ -28,6 +28,7 @@
|
|||||||
<service id="data_collector.events" class="Symfony\Component\HttpKernel\DataCollector\EventDataCollector">
|
<service id="data_collector.events" class="Symfony\Component\HttpKernel\DataCollector\EventDataCollector">
|
||||||
<tag name="data_collector" template="@WebProfiler/Collector/events.html.twig" id="events" priority="290" />
|
<tag name="data_collector" template="@WebProfiler/Collector/events.html.twig" id="events" priority="290" />
|
||||||
<argument type="service" id="debug.event_dispatcher" on-invalid="ignore" />
|
<argument type="service" id="debug.event_dispatcher" on-invalid="ignore" />
|
||||||
|
<argument type="service" id="request_stack" on-invalid="ignore" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="data_collector.logger" class="Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector">
|
<service id="data_collector.logger" class="Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector">
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
<argument type="service" id="debug.event_dispatcher.inner" />
|
<argument type="service" id="debug.event_dispatcher.inner" />
|
||||||
<argument type="service" id="debug.stopwatch" />
|
<argument type="service" id="debug.stopwatch" />
|
||||||
<argument type="service" id="logger" on-invalid="null" />
|
<argument type="service" id="logger" on-invalid="null" />
|
||||||
|
<argument type="service" id="request_stack" on-invalid="null" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="debug.controller_resolver" decorates="controller_resolver" class="Symfony\Component\HttpKernel\Controller\TraceableControllerResolver">
|
<service id="debug.controller_resolver" decorates="controller_resolver" class="Symfony\Component\HttpKernel\Controller\TraceableControllerResolver">
|
||||||
|
@ -13,10 +13,12 @@ namespace Symfony\Component\EventDispatcher\Debug;
|
|||||||
|
|
||||||
use Psr\EventDispatcher\StoppableEventInterface;
|
use Psr\EventDispatcher\StoppableEventInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\BrowserKit\Request;
|
||||||
use Symfony\Component\EventDispatcher\Event;
|
use Symfony\Component\EventDispatcher\Event;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
|
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
use Symfony\Component\Stopwatch\Stopwatch;
|
use Symfony\Component\Stopwatch\Stopwatch;
|
||||||
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
|
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
|
||||||
|
|
||||||
@ -36,14 +38,17 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
private $dispatcher;
|
private $dispatcher;
|
||||||
private $wrappedListeners;
|
private $wrappedListeners;
|
||||||
private $orphanedEvents;
|
private $orphanedEvents;
|
||||||
|
private $requestStack;
|
||||||
|
private $currentRequestHash = '';
|
||||||
|
|
||||||
public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null)
|
public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null, RequestStack $requestStack = null)
|
||||||
{
|
{
|
||||||
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
|
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
|
||||||
$this->stopwatch = $stopwatch;
|
$this->stopwatch = $stopwatch;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->wrappedListeners = [];
|
$this->wrappedListeners = [];
|
||||||
$this->orphanedEvents = [];
|
$this->orphanedEvents = [];
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,6 +138,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
$this->callStack = new \SplObjectStorage();
|
$this->callStack = new \SplObjectStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : '';
|
||||||
$eventName = 1 < \func_num_args() ? \func_get_arg(1) : null;
|
$eventName = 1 < \func_num_args() ? \func_get_arg(1) : null;
|
||||||
|
|
||||||
if (\is_object($event)) {
|
if (\is_object($event)) {
|
||||||
@ -168,6 +174,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
$this->afterDispatch($eventName, $event);
|
$this->afterDispatch($eventName, $event);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
$this->currentRequestHash = $currentRequestHash;
|
||||||
$this->postProcess($eventName);
|
$this->postProcess($eventName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,18 +183,22 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param Request|null $request The request to get listeners for
|
||||||
*/
|
*/
|
||||||
public function getCalledListeners()
|
public function getCalledListeners(/* Request $request = null */)
|
||||||
{
|
{
|
||||||
if (null === $this->callStack) {
|
if (null === $this->callStack) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hash = 1 <= \func_num_args() && null !== ($request = \func_get_arg(0)) ? spl_object_hash($request) : null;
|
||||||
$called = [];
|
$called = [];
|
||||||
foreach ($this->callStack as $listener) {
|
foreach ($this->callStack as $listener) {
|
||||||
list($eventName) = $this->callStack->getInfo();
|
list($eventName, $requestHash) = $this->callStack->getInfo();
|
||||||
|
if (null === $hash || $hash === $requestHash) {
|
||||||
$called[] = $listener->getInfo($eventName);
|
$called[] = $listener->getInfo($eventName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $called;
|
return $called;
|
||||||
@ -195,8 +206,10 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param Request|null $request The request to get listeners for
|
||||||
*/
|
*/
|
||||||
public function getNotCalledListeners()
|
public function getNotCalledListeners(/* Request $request = null */)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$allListeners = $this->getListeners();
|
$allListeners = $this->getListeners();
|
||||||
@ -209,13 +222,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hash = 1 <= \func_num_args() && null !== ($request = \func_get_arg(0)) ? spl_object_hash($request) : null;
|
||||||
$notCalled = [];
|
$notCalled = [];
|
||||||
foreach ($allListeners as $eventName => $listeners) {
|
foreach ($allListeners as $eventName => $listeners) {
|
||||||
foreach ($listeners as $listener) {
|
foreach ($listeners as $listener) {
|
||||||
$called = false;
|
$called = false;
|
||||||
if (null !== $this->callStack) {
|
if (null !== $this->callStack) {
|
||||||
foreach ($this->callStack as $calledListener) {
|
foreach ($this->callStack as $calledListener) {
|
||||||
if ($calledListener->getWrappedListener() === $listener) {
|
list(, $requestHash) = $this->callStack->getInfo();
|
||||||
|
if ((null === $hash || $hash === $requestHash) && $calledListener->getWrappedListener() === $listener) {
|
||||||
$called = true;
|
$called = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -237,15 +252,27 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
return $notCalled;
|
return $notCalled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOrphanedEvents(): array
|
/**
|
||||||
|
* @param Request|null $request The request to get orphaned events for
|
||||||
|
*/
|
||||||
|
public function getOrphanedEvents(/* Request $request = null */): array
|
||||||
{
|
{
|
||||||
return $this->orphanedEvents;
|
if (1 <= \func_num_args() && null !== $request = \func_get_arg(0)) {
|
||||||
|
return $this->orphanedEvents[spl_object_hash($request)] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->orphanedEvents) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge(...array_values($this->orphanedEvents));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reset()
|
public function reset()
|
||||||
{
|
{
|
||||||
$this->callStack = null;
|
$this->callStack = null;
|
||||||
$this->orphanedEvents = [];
|
$this->orphanedEvents = [];
|
||||||
|
$this->currentRequestHash = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -298,7 +325,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
private function preProcess($eventName)
|
private function preProcess($eventName)
|
||||||
{
|
{
|
||||||
if (!$this->dispatcher->hasListeners($eventName)) {
|
if (!$this->dispatcher->hasListeners($eventName)) {
|
||||||
$this->orphanedEvents[] = $eventName;
|
$this->orphanedEvents[$this->currentRequestHash][] = $eventName;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -309,7 +336,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
$this->wrappedListeners[$eventName][] = $wrappedListener;
|
$this->wrappedListeners[$eventName][] = $wrappedListener;
|
||||||
$this->dispatcher->removeListener($eventName, $listener);
|
$this->dispatcher->removeListener($eventName, $listener);
|
||||||
$this->dispatcher->addListener($eventName, $wrappedListener, $priority);
|
$this->dispatcher->addListener($eventName, $wrappedListener, $priority);
|
||||||
$this->callStack->attach($wrappedListener, [$eventName]);
|
$this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,10 +361,6 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
|
|||||||
if (null !== $this->logger) {
|
if (null !== $this->logger) {
|
||||||
$this->logger->debug('Notified event "{event}" to listener "{listener}".', $context);
|
$this->logger->debug('Notified event "{event}" to listener "{listener}".', $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($this->called[$eventName])) {
|
|
||||||
$this->called[$eventName] = new \SplObjectStorage();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$this->callStack->detach($listener);
|
$this->callStack->detach($listener);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Component\EventDispatcher\Debug;
|
namespace Symfony\Component\EventDispatcher\Debug;
|
||||||
|
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Contracts\Service\ResetInterface;
|
use Symfony\Contracts\Service\ResetInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,14 +25,18 @@ interface TraceableEventDispatcherInterface extends EventDispatcherInterface, Re
|
|||||||
/**
|
/**
|
||||||
* Gets the called listeners.
|
* Gets the called listeners.
|
||||||
*
|
*
|
||||||
|
* @param Request|null $request The request to get listeners for
|
||||||
|
*
|
||||||
* @return array An array of called listeners
|
* @return array An array of called listeners
|
||||||
*/
|
*/
|
||||||
public function getCalledListeners();
|
public function getCalledListeners(/* Request $request = null */);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the not called listeners.
|
* Gets the not called listeners.
|
||||||
*
|
*
|
||||||
|
* @param Request|null $request The request to get listeners for
|
||||||
|
*
|
||||||
* @return array An array of not called listeners
|
* @return array An array of not called listeners
|
||||||
*/
|
*/
|
||||||
public function getNotCalledListeners();
|
public function getNotCalledListeners(/* Request $request = null */);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"symfony/dependency-injection": "~3.4|~4.0",
|
"symfony/dependency-injection": "~3.4|~4.0",
|
||||||
"symfony/expression-language": "~3.4|~4.0",
|
"symfony/expression-language": "~3.4|~4.0",
|
||||||
"symfony/config": "~3.4|~4.0",
|
"symfony/config": "~3.4|~4.0",
|
||||||
|
"symfony/http-foundation": "^3.4|^4.0",
|
||||||
"symfony/stopwatch": "~3.4|~4.0",
|
"symfony/stopwatch": "~3.4|~4.0",
|
||||||
"psr/log": "~1.0"
|
"psr/log": "~1.0"
|
||||||
},
|
},
|
||||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\HttpKernel\DataCollector;
|
|||||||
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
|
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
|
||||||
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\Service\ResetInterface;
|
use Symfony\Contracts\Service\ResetInterface;
|
||||||
@ -26,10 +27,13 @@ use Symfony\Contracts\Service\ResetInterface;
|
|||||||
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
|
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||||
{
|
{
|
||||||
protected $dispatcher;
|
protected $dispatcher;
|
||||||
|
private $requestStack;
|
||||||
|
private $currentRequest;
|
||||||
|
|
||||||
public function __construct(EventDispatcherInterface $dispatcher = null)
|
public function __construct(EventDispatcherInterface $dispatcher = null, RequestStack $requestStack = null)
|
||||||
{
|
{
|
||||||
$this->dispatcher = $dispatcher;
|
$this->dispatcher = $dispatcher;
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,6 +41,7 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
|
|||||||
*/
|
*/
|
||||||
public function collect(Request $request, Response $response, \Exception $exception = null)
|
public function collect(Request $request, Response $response, \Exception $exception = null)
|
||||||
{
|
{
|
||||||
|
$this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null;
|
||||||
$this->data = [
|
$this->data = [
|
||||||
'called_listeners' => [],
|
'called_listeners' => [],
|
||||||
'not_called_listeners' => [],
|
'not_called_listeners' => [],
|
||||||
@ -56,12 +61,12 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
|
|||||||
public function lateCollect()
|
public function lateCollect()
|
||||||
{
|
{
|
||||||
if ($this->dispatcher instanceof TraceableEventDispatcherInterface) {
|
if ($this->dispatcher instanceof TraceableEventDispatcherInterface) {
|
||||||
$this->setCalledListeners($this->dispatcher->getCalledListeners());
|
$this->setCalledListeners($this->dispatcher->getCalledListeners($this->currentRequest));
|
||||||
$this->setNotCalledListeners($this->dispatcher->getNotCalledListeners());
|
$this->setNotCalledListeners($this->dispatcher->getNotCalledListeners($this->currentRequest));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->dispatcher instanceof TraceableEventDispatcher) {
|
if ($this->dispatcher instanceof TraceableEventDispatcher) {
|
||||||
$this->setOrphanedEvents($this->dispatcher->getOrphanedEvents());
|
$this->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->data = $this->cloneVar($this->data);
|
$this->data = $this->cloneVar($this->data);
|
||||||
|
Reference in New Issue
Block a user