diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig
index e58ffae11caf6..39d341f28c2b2 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig
@@ -63,7 +63,7 @@
- Main Request
+ {{ profile.parent ? "Request" : "Main Request" }}
- {{ collector.events.__section__.totaltime }} ms
{% if profile.parent %}
diff --git a/src/Symfony/Component/HttpKernel/Debug/ContainerAwareTraceableEventDispatcher.php b/src/Symfony/Component/HttpKernel/Debug/ContainerAwareTraceableEventDispatcher.php
index e9b1d8fe657ed..66ea7b63528bc 100644
--- a/src/Symfony/Component/HttpKernel/Debug/ContainerAwareTraceableEventDispatcher.php
+++ b/src/Symfony/Component/HttpKernel/Debug/ContainerAwareTraceableEventDispatcher.php
@@ -13,7 +13,9 @@
use Symfony\Component\HttpKernel\Debug\Stopwatch;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\HttpKernel\Profiler\Profiler;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
@@ -30,6 +32,7 @@ class ContainerAwareTraceableEventDispatcher extends ContainerAwareEventDispatch
private $called;
private $stopwatch;
private $priorities;
+ private $profiler;
/**
* Constructor.
@@ -83,11 +86,18 @@ public function dispatch($eventName, Event $event = null)
case 'kernel.response':
$token = $event->getResponse()->headers->get('X-Debug-Token');
$this->stopwatch->stopSection($token);
- $this->updateProfile($token);
+ if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) {
+ // The profiles can only be updated once they have been created
+ // that is after the 'kernel.response' event of the main request
+ $this->updateProfiles($token, true);
+ }
break;
case 'kernel.terminate':
$this->stopwatch->stopSection($token);
- $this->updateProfile($token);
+ // The children profiles have been updated by the previous 'kernel.response'
+ // event. Only the root profile need to be updated with the 'kernel.terminate'
+ // timing informations.
+ $this->updateProfiles($token, false);
break;
}
@@ -255,28 +265,41 @@ private function getListenerInfo($listener, $eventName)
}
/**
- * Updates the profile data.
+ * Updates the stopwatch data in the profile hierarchy.
*
- * @param string $token Profile token
+ * @param string $token Profile token
+ * @param Boolean $updateChildren Whether to update the children altogether
*/
- private function updateProfile($token)
+ private function updateProfiles($token, $updateChildren)
{
if (!$this->getContainer()->has('profiler')) {
return;
}
- $profiler = $this->getContainer()->get('profiler');
- if (!$profile = $profiler->loadProfile($token)) {
+ $this->profiler = $this->getContainer()->get('profiler');
+
+ if (!$profile = $this->profiler->loadProfile($token)) {
return;
}
- $profile->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($token));
- $profiler->saveProfile($profile);
+ $this->saveStopwatchInfoInProfile($profile, $updateChildren);
+ }
- // children
- foreach ($profile->getChildren() as $child) {
- $child->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($child->getToken()));
- $profiler->saveProfile($child);
+ /**
+ * Update the profiles with the timing info and saves them.
+ *
+ * @param Profile $profile The root profile
+ * @param Boolean $updateChildren Whether to update the children altogether
+ */
+ private function saveStopwatchInfoInProfile(Profile $profile, $updateChildren)
+ {
+ $profile->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($profile->getToken()));
+ $this->profiler->saveProfile($profile);
+
+ if ($updateChildren) {
+ foreach ($profile->getChildren() as $child) {
+ $this->saveStopwatchInfoInProfile($child, true);
+ }
}
}
diff --git a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
index dbbb441889e7d..83ee82a8d42c9 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
@@ -16,6 +16,7 @@
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\HttpKernel\Profiler\Profiler;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -34,6 +35,7 @@ class ProfilerListener implements EventSubscriberInterface
protected $exception;
protected $children;
protected $requests;
+ protected $profiles;
/**
* Constructor.
@@ -50,6 +52,7 @@ public function __construct(Profiler $profiler, RequestMatcherInterface $matcher
$this->onlyException = (Boolean) $onlyException;
$this->onlyMasterRequests = (Boolean) $onlyMasterRequests;
$this->children = new \SplObjectStorage();
+ $this->profiles = array();
}
/**
@@ -99,6 +102,16 @@ public function onKernelResponse(FilterResponseEvent $event)
return;
}
+ $this->profiles[] = $profile;
+
+ if (null !== $exception) {
+ foreach ($this->profiles as $profile) {
+ $this->profiler->saveProfile($profile);
+ }
+
+ return;
+ }
+
// keep the profile as the child of its parent
if (!$master) {
array_pop($this->requests);
@@ -109,17 +122,16 @@ public function onKernelResponse(FilterResponseEvent $event)
$this->children[$parent] = $profiles;
}
- // store the profile and its children
if (isset($this->children[$request])) {
foreach ($this->children[$request] as $child) {
- $child->setParent($profile);
$profile->addChild($child);
- $this->profiler->saveProfile($child);
}
$this->children[$request] = array();
}
- $this->profiler->saveProfile($profile);
+ if ($master) {
+ $this->saveProfiles($profile);
+ }
}
static public function getSubscribedEvents()
@@ -128,9 +140,21 @@ static public function getSubscribedEvents()
// kernel.request must be registered as early as possible to not break
// when an exception is thrown in any other kernel.request listener
KernelEvents::REQUEST => array('onKernelRequest', 1024),
-
KernelEvents::RESPONSE => array('onKernelResponse', -100),
KernelEvents::EXCEPTION => 'onKernelException',
);
}
+
+ /**
+ * Saves the profile hierarchy.
+ *
+ * @param Profile $profile The root profile
+ */
+ private function saveProfiles(Profile $profile)
+ {
+ $this->profiler->saveProfile($profile);
+ foreach ($profile->getChildren() as $profile) {
+ $this->saveProfiles($profile);
+ }
+ }
}