From 7188e19536961d70614483d240433cba8be50187 Mon Sep 17 00:00:00 2001 From: clombardot Date: Fri, 16 Mar 2012 12:32:50 +0100 Subject: [PATCH 1/3] Allow to show explain plans on each queries --- Controller/PanelController.php | 41 ++++++++++++++++++++++ PropelBundle.php | 1 + Resources/views/Collector/propel.html.twig | 37 +++++++++++++++++-- Resources/views/Panel/explain.html.twig | 16 +++++++++ 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 Resources/views/Panel/explain.html.twig diff --git a/Controller/PanelController.php b/Controller/PanelController.php index cd04c47..a2eda52 100644 --- a/Controller/PanelController.php +++ b/Controller/PanelController.php @@ -12,6 +12,7 @@ namespace Propel\PropelBundle\Controller; use Symfony\Bridge\Propel1\DataCollector\PropelDataCollector; use Symfony\Component\DependencyInjection\ContainerAware; +use Symfony\Component\HttpFoundation\Response; /** * PanelController is designed to display information in the Propel Panel. @@ -39,4 +40,44 @@ class PanelController extends ContainerAware ); } + /** + * Renders the profiler panel for the given token. + * + * @param string $token The profiler token + * @param string $connection The connection name + * @param integer $query + * + * @return Response A Response instance + */ + public function explainAction($token, $connection, $query) + { + $profiler = $this->container->get('profiler'); + $profiler->disable(); + + $profile = $profiler->loadProfile($token); + $queries = $profile->getCollector('propel')->getQueries(); + + if (!isset($queries[$query])) { + return new Response('This query does not exist.'); + } + + // Open the connection + $con = \Propel::getConnection($connection); + + // Get the adapter + $db = \Propel::getDB($connection); + + try { + $stmt = $db->doExplainPlan($con, $queries[$query]['sql']); + $results = $stmt->fetchAll(\PDO::FETCH_ASSOC); + } catch (\Exception $e) { + return new Response('
This query cannot be explained.
'); + } + + return $this->container->get('templating')->renderResponse('PropelBundle:Panel:explain.html.twig', array( + 'data' => $results, + 'query' => $query, + )); + + } } diff --git a/PropelBundle.php b/PropelBundle.php index ba78dbe..1680a45 100644 --- a/PropelBundle.php +++ b/PropelBundle.php @@ -48,6 +48,7 @@ class PropelBundle extends Bundle $config->setParameter('debugpdo.logging.details', array( 'time' => array('enabled' => true), 'mem' => array('enabled' => true), + 'connection' => array('enabled' => true), )); \Propel::setLogger($this->container->get('propel.logger')); diff --git a/Resources/views/Collector/propel.html.twig b/Resources/views/Collector/propel.html.twig index 40049bc..7932626 100644 --- a/Resources/views/Collector/propel.html.twig +++ b/Resources/views/Collector/propel.html.twig @@ -41,6 +41,23 @@ font-size: 0.9em; margin: 3px 0; } + + .SQLExplain { + margin: 5px; + } + + .SQLExplain .error { + background-color: #F2DEDE; + border-color: #EED3D7; + color: #B94A48; + padding: 8px 35px 8px 14px; + font-weight: bold; + } + + #content .SQLExplain h2 { + font-size: 17px; + margin-bottom: 0; + }

Queries

@@ -54,11 +71,27 @@ {% if not collector.querycount %} No queries. {% else %} - {% for query in collector.queries %} + {% for i, query in collector.queries %} {{ query.sql|format_sql }} -
Time: {{ query.time }} - Memory: {{ query.memory }}
+ {% if app.request.query.has('query') and app.request.query.get('query') == i %} +
+ {% render 'PropelBundle:Panel:explain' with { + 'token': token, + 'panel': 'propel', + 'query': app.request.query.get('query'), + 'connection': app.request.query.get('connection') + } %} +
+ {% endif %} +
+ Time: {{ query.time }} - Memory: {{ query.memory }} - Connection: {{ query.connection }} + + {% if app.request.query.get('query', -1) != i %} + - Explain the query + {% endif %} +
{% endfor %} diff --git a/Resources/views/Panel/explain.html.twig b/Resources/views/Panel/explain.html.twig new file mode 100644 index 0000000..0c132d7 --- /dev/null +++ b/Resources/views/Panel/explain.html.twig @@ -0,0 +1,16 @@ +

Explanation

+ + + + {% for label in data[0]|keys %} + + {% endfor %} + + {% for row in data %} + + {% for item in row %} + + {% endfor %} + + {% endfor %} +
{{ label }}
{{ item }}
\ No newline at end of file From f114112c991e3522fff358bfe41f2ca0725274c2 Mon Sep 17 00:00:00 2001 From: clombardot Date: Mon, 19 Mar 2012 09:45:20 +0100 Subject: [PATCH 2/3] Fix phpdoc --- Controller/PanelController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Controller/PanelController.php b/Controller/PanelController.php index a2eda52..4a84943 100644 --- a/Controller/PanelController.php +++ b/Controller/PanelController.php @@ -47,7 +47,7 @@ class PanelController extends ContainerAware * @param string $connection The connection name * @param integer $query * - * @return Response A Response instance + * @return Symfony\Component\HttpFoundation\Response A Response instance */ public function explainAction($token, $connection, $query) { From 295f732279398fd110047f101019a3206c62483d Mon Sep 17 00:00:00 2001 From: clombardot Date: Mon, 19 Mar 2012 09:52:02 +0100 Subject: [PATCH 3/3] Add an achor to return at the good query running explain --- Resources/views/Collector/propel.html.twig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/views/Collector/propel.html.twig b/Resources/views/Collector/propel.html.twig index 7932626..9db6a04 100644 --- a/Resources/views/Collector/propel.html.twig +++ b/Resources/views/Collector/propel.html.twig @@ -74,6 +74,7 @@ {% for i, query in collector.queries %} + {{ query.sql|format_sql }} {% if app.request.query.has('query') and app.request.query.get('query') == i %}
@@ -89,7 +90,7 @@ Time: {{ query.time }} - Memory: {{ query.memory }} - Connection: {{ query.connection }} {% if app.request.query.get('query', -1) != i %} - - Explain the query + - Explain the query {% endif %}