diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml
index c745949b43116..17df61db1c13a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml
@@ -28,6 +28,7 @@
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml
index 9b39912087110..abd0733e0cbd3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml
@@ -12,6 +12,7 @@
+
diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
index e0a161ebde478..e5b79276c62c9 100644
--- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
@@ -13,10 +13,12 @@
use Psr\EventDispatcher\StoppableEventInterface;
use Psr\Log\LoggerInterface;
+use Symfony\Component\BrowserKit\Request;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
+use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
@@ -36,14 +38,17 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
private $dispatcher;
private $wrappedListeners;
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->stopwatch = $stopwatch;
$this->logger = $logger;
$this->wrappedListeners = [];
$this->orphanedEvents = [];
+ $this->requestStack = $requestStack;
}
/**
@@ -133,6 +138,7 @@ public function dispatch($event/*, string $eventName = null*/)
$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;
if (\is_object($event)) {
@@ -168,6 +174,7 @@ public function dispatch($event/*, string $eventName = null*/)
$this->afterDispatch($eventName, $event);
}
} finally {
+ $this->currentRequestHash = $currentRequestHash;
$this->postProcess($eventName);
}
@@ -176,18 +183,22 @@ public function dispatch($event/*, string $eventName = null*/)
/**
* {@inheritdoc}
+ *
+ * @param Request|null $request The request to get listeners for
*/
- public function getCalledListeners()
+ public function getCalledListeners(/* Request $request = null */)
{
if (null === $this->callStack) {
return [];
}
+ $hash = 1 <= \func_num_args() && null !== ($request = \func_get_arg(0)) ? spl_object_hash($request) : null;
$called = [];
foreach ($this->callStack as $listener) {
- list($eventName) = $this->callStack->getInfo();
-
- $called[] = $listener->getInfo($eventName);
+ list($eventName, $requestHash) = $this->callStack->getInfo();
+ if (null === $hash || $hash === $requestHash) {
+ $called[] = $listener->getInfo($eventName);
+ }
}
return $called;
@@ -195,8 +206,10 @@ public function getCalledListeners()
/**
* {@inheritdoc}
+ *
+ * @param Request|null $request The request to get listeners for
*/
- public function getNotCalledListeners()
+ public function getNotCalledListeners(/* Request $request = null */)
{
try {
$allListeners = $this->getListeners();
@@ -209,13 +222,15 @@ public function getNotCalledListeners()
return [];
}
+ $hash = 1 <= \func_num_args() && null !== ($request = \func_get_arg(0)) ? spl_object_hash($request) : null;
$notCalled = [];
foreach ($allListeners as $eventName => $listeners) {
foreach ($listeners as $listener) {
$called = false;
if (null !== $this->callStack) {
foreach ($this->callStack as $calledListener) {
- if ($calledListener->getWrappedListener() === $listener) {
+ list(, $requestHash) = $this->callStack->getInfo();
+ if ((null === $hash || $hash === $requestHash) && $calledListener->getWrappedListener() === $listener) {
$called = true;
break;
@@ -237,15 +252,27 @@ public function getNotCalledListeners()
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()
{
$this->callStack = null;
$this->orphanedEvents = [];
+ $this->currentRequestHash = '';
}
/**
@@ -298,7 +325,7 @@ protected function postDispatch($eventName, Event $event)
private function preProcess($eventName)
{
if (!$this->dispatcher->hasListeners($eventName)) {
- $this->orphanedEvents[] = $eventName;
+ $this->orphanedEvents[$this->currentRequestHash][] = $eventName;
return;
}
@@ -309,7 +336,7 @@ private function preProcess($eventName)
$this->wrappedListeners[$eventName][] = $wrappedListener;
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName, $wrappedListener, $priority);
- $this->callStack->attach($wrappedListener, [$eventName]);
+ $this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]);
}
}
@@ -334,10 +361,6 @@ private function postProcess($eventName)
if (null !== $this->logger) {
$this->logger->debug('Notified event "{event}" to listener "{listener}".', $context);
}
-
- if (!isset($this->called[$eventName])) {
- $this->called[$eventName] = new \SplObjectStorage();
- }
} else {
$this->callStack->detach($listener);
}
diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php
index cd4d7470afed2..4fedb9a413a3b 100644
--- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php
+++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\EventDispatcher\Debug;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\Service\ResetInterface;
/**
@@ -24,14 +25,18 @@ interface TraceableEventDispatcherInterface extends EventDispatcherInterface, Re
/**
* Gets the called listeners.
*
+ * @param Request|null $request The request to get listeners for
+ *
* @return array An array of called listeners
*/
- public function getCalledListeners();
+ public function getCalledListeners(/* Request $request = null */);
/**
* Gets the not called listeners.
*
+ * @param Request|null $request The request to get listeners for
+ *
* @return array An array of not called listeners
*/
- public function getNotCalledListeners();
+ public function getNotCalledListeners(/* Request $request = null */);
}
diff --git a/src/Symfony/Component/EventDispatcher/composer.json b/src/Symfony/Component/EventDispatcher/composer.json
index 163149f412beb..6677e2b74f636 100644
--- a/src/Symfony/Component/EventDispatcher/composer.json
+++ b/src/Symfony/Component/EventDispatcher/composer.json
@@ -23,6 +23,7 @@
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/config": "~3.4|~4.0",
+ "symfony/http-foundation": "^3.4|^4.0",
"symfony/stopwatch": "~3.4|~4.0",
"psr/log": "~1.0"
},
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php
index 8e84c6acf6973..d918ddf786634 100644
--- a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php
@@ -14,6 +14,7 @@
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Service\ResetInterface;
@@ -26,10 +27,13 @@
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
{
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->requestStack = $requestStack;
}
/**
@@ -37,6 +41,7 @@ public function __construct(EventDispatcherInterface $dispatcher = null)
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
{
+ $this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null;
$this->data = [
'called_listeners' => [],
'not_called_listeners' => [],
@@ -56,12 +61,12 @@ public function reset()
public function lateCollect()
{
if ($this->dispatcher instanceof TraceableEventDispatcherInterface) {
- $this->setCalledListeners($this->dispatcher->getCalledListeners());
- $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners());
+ $this->setCalledListeners($this->dispatcher->getCalledListeners($this->currentRequest));
+ $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners($this->currentRequest));
}
if ($this->dispatcher instanceof TraceableEventDispatcher) {
- $this->setOrphanedEvents($this->dispatcher->getOrphanedEvents());
+ $this->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest));
}
$this->data = $this->cloneVar($this->data);