From a8eff2b154a2b1aa029f38641fb332fa762cab41 Mon Sep 17 00:00:00 2001 From: noel guilbert Date: Sat, 26 Feb 2011 17:24:02 +0100 Subject: [PATCH] Improved profiler to store and retrieve sub requests data --- .../Profiler/ProfilerListener.php | 25 ++++++++--- .../Resources/config/profiling.xml | 1 + .../views/Collector/request.html.twig | 17 +++++++ .../DependencyInjection/Container.php | 16 +++++++ .../HttpKernel/Profiler/Profiler.php | 45 ++++++++++++++++++- .../Profiler/ProfilerStorageInterface.php | 9 ++++ .../Profiler/SqliteProfilerStorage.php | 19 ++++++-- 7 files changed, 122 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Profiler/ProfilerListener.php b/src/Symfony/Bundle/FrameworkBundle/Profiler/ProfilerListener.php index 22167fdca9..33a5b20b79 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Profiler/ProfilerListener.php +++ b/src/Symfony/Bundle/FrameworkBundle/Profiler/ProfilerListener.php @@ -46,6 +46,19 @@ class ProfilerListener $this->onlyException = $onlyException; } + /** + * Handles the core.request event + * + * This method initialize the profiler to be able to get it as a scoped + * service when handleResponse() will collect the sub request + * + * @param EventInterface $event An EventInterface instance + */ + public function handleRequest(EventInterface $event) + { + $this->container->get('profiler'); + } + /** * Handles the core.exception event. * @@ -71,10 +84,6 @@ class ProfilerListener */ public function handleResponse(EventInterface $event, Response $response) { - if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type')) { - return $response; - } - if (null !== $this->matcher && !$this->matcher->matches($event->get('request'))) { return $response; } @@ -83,7 +92,13 @@ class ProfilerListener return $response; } - $this->container->get('profiler')->collect($event->get('request'), $response, $this->exception); + $profiler = $this->container->get('profiler'); + + if (($parent = $this->container->getCurrentScopedStack('request'))) { + $profiler->setParent($parent['request']['profiler']->getToken()); + } + + $profiler->collect($event->get('request'), $response, $this->exception); $this->exception = null; return $response; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml index 72794e98ff..d2e5026818 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.xml @@ -27,6 +27,7 @@ + %profiler_listener.only_exceptions% diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig index fea19f2a2b..30435c246b 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig @@ -76,4 +76,21 @@ Request {% else %} No request session attributes {% endif %} + + + {% if profiler.parent %} +

Parent request: {{ profiler.parent }}

+ + {% include 'WebProfilerBundle:Profiler:bag.html.twig' with { 'bag': profiler.parenttoken.get('request').requestattributes } only %} + {% endif %} + + {% if profiler.children|length %} +

Sub requests

+ + {% for subrequest in profiler.children %} +

{{ subrequest.token }}

+ {% include 'WebProfilerBundle:Profiler:bag.html.twig' with { 'bag': subrequest.get('request').requestattributes } only %} + {% endfor %} + {% endif %} + {% endblock %} diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 321fceb608..c1ed6b40d2 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -295,6 +295,22 @@ class Container implements ContainerInterface $this->scopedServices[$name] = array(); } + + /** + * Returns the current stacked service scope for the given name + * + * @param string $name The service name + * @return array The service scope + */ + public function getCurrentScopedStack($name) + { + if (!isset($this->scopeStacks[$name]) || 0 === $this->scopeStacks[$name]->count()) { + return null; + } + + return $this->scopeStacks[$name]->current(); + } + /** * This is called to leave the current scope, and move back to the parent * scope. diff --git a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php index 6c256b7b28..e82b22e837 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php +++ b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php @@ -35,6 +35,7 @@ class Profiler protected $url; protected $time; protected $empty; + protected $children; /** * Constructor. @@ -142,7 +143,7 @@ class Profiler $this->token = $token; if (false !== $items = $this->storage->read($token)) { - list($data, $this->ip, $this->url, $this->time) = $items; + list($data, $this->parent, $this->ip, $this->url, $this->time) = $items; $this->set(unserialize(base64_decode($data))); $this->empty = false; @@ -151,6 +152,30 @@ class Profiler } } + /** + * Sets the parent token + * + * @param string $parent The parent token + */ + public function setParent($parent) + { + $this->parent = $parent; + } + + /** + * Returns an instance of the parent token + * + * @return Profiler + */ + public function getParentToken() + { + if (null !== $this->parent) { + return $this->loadFromToken($this->parent); + } + + return null; + } + /** * Gets the token. * @@ -229,6 +254,23 @@ class Profiler return $this->storage->find($ip, $url, $limit); } + /** + * Finds children profilers. + * + * @return array An array of Profiler + */ + public function getChildren() + { + if (null === $this->children) { + $this->children = array(); + foreach ($this->storage->findChildren($this->token) as $token) { + $this->children[] = $this->loadFromToken($token['token']); + } + } + + return $this->children; + } + /** * Collects data for the given Response. * @@ -248,7 +290,6 @@ class Profiler $collector->collect($request, $response, $exception); } - $this->parent = ''; $this->ip = $request->server->get('REMOTE_ADDR'); $this->url = $request->getUri(); $this->time = time(); diff --git a/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface.php b/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface.php index 1fbd2a0ae4..830fa198d5 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface.php +++ b/src/Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface.php @@ -29,6 +29,15 @@ interface ProfilerStorageInterface */ function find($ip, $url, $limit); + /** + * Finds profiler tokens for the given parent token. + * + * @param string $token The parent token + * + * @return array An array of tokens + */ + function findChildren($token); + /** * Reads data associated with the given token. * diff --git a/src/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.php index bc01087ac8..fbd2fca82e 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.php +++ b/src/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.php @@ -56,7 +56,7 @@ class SqliteProfilerStorage implements ProfilerStorageInterface $criteria = $criteria ? 'WHERE '.implode(' AND ', $criteria) : ''; $db = $this->initDb(); - $tokens = $this->fetch($db, 'SELECT token, ip, url, time FROM data '.$criteria.' ORDER BY time DESC LIMIT '.((integer) $limit), $args); + $tokens = $this->fetch($db, 'SELECT token, ip, url, time, parent FROM data '.$criteria.' ORDER BY time DESC LIMIT '.((integer) $limit), $args); $this->close($db); return $tokens; @@ -69,15 +69,28 @@ class SqliteProfilerStorage implements ProfilerStorageInterface { $db = $this->initDb(); $args = array(':token' => $token); - $data = $this->fetch($db, 'SELECT data, ip, url, time FROM data WHERE token = :token LIMIT 1', $args); + $data = $this->fetch($db, 'SELECT data, parent, ip, url, time FROM data WHERE token = :token LIMIT 1', $args); $this->close($db); if (isset($data[0]['data'])) { - return array($data[0]['data'], $data[0]['ip'], $data[0]['url'], $data[0]['time']); + return array($data[0]['data'], $data[0]['parent'], $data[0]['ip'], $data[0]['url'], $data[0]['time']); } else { return false; } } + /** + * {@inheritdoc} + */ + public function findChildren($token) + { + $db = $this->initDb(); + $args = array(':token' => $token); + $tokens = $this->fetch($db, 'SELECT token FROM data WHERE parent = :token LIMIT 1', $args); + $this->close($db); + + return $tokens; + } + /** * {@inheritdoc} */