added a Twig panel to the WebProfiler
This commit is contained in:
parent
ef0c9679cb
commit
daad64fa54
@ -1,10 +1,4 @@
|
|||||||
{
|
{
|
||||||
"repositories": [
|
|
||||||
{
|
|
||||||
"type": "vcs",
|
|
||||||
"url": "https://github.com/fabpot/Twig"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "symfony/symfony",
|
"name": "symfony/symfony",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"description": "The Symfony PHP framework",
|
"description": "The Symfony PHP framework",
|
||||||
@ -24,7 +18,7 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.9",
|
"php": ">=5.3.9",
|
||||||
"doctrine/common": "~2.3",
|
"doctrine/common": "~2.3",
|
||||||
"twig/twig": "dev-profiler as 1.17.x-dev",
|
"twig/twig": "~1.18",
|
||||||
"psr/log": "~1.0"
|
"psr/log": "~1.0"
|
||||||
},
|
},
|
||||||
"replace": {
|
"replace": {
|
||||||
|
143
src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php
Normal file
143
src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Twig\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TwigDataCollector.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class TwigDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||||
|
{
|
||||||
|
private $profile;
|
||||||
|
private $computed;
|
||||||
|
|
||||||
|
public function __construct(\Twig_Profiler_Profile $profile)
|
||||||
|
{
|
||||||
|
$this->profile = $profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function collect(Request $request, Response $response, \Exception $exception = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function lateCollect()
|
||||||
|
{
|
||||||
|
$this->data['profile'] = serialize($this->profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTime()
|
||||||
|
{
|
||||||
|
return $this->getProfile()->getDuration() * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplateCount()
|
||||||
|
{
|
||||||
|
return $this->getComputedData('template_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplates()
|
||||||
|
{
|
||||||
|
return $this->getComputedData('templates');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlockCount()
|
||||||
|
{
|
||||||
|
return $this->getComputedData('block_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMacroCount()
|
||||||
|
{
|
||||||
|
return $this->getComputedData('macro_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHtmlCallGraph()
|
||||||
|
{
|
||||||
|
$dumper = new \Twig_Profiler_Dumper_Html();
|
||||||
|
|
||||||
|
return new \Twig_Markup($dumper->dump($this->getProfile()), 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProfile()
|
||||||
|
{
|
||||||
|
if (null === $this->profile) {
|
||||||
|
$this->profile = unserialize($this->data['profile']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getComputedData($index)
|
||||||
|
{
|
||||||
|
if (null === $this->computed) {
|
||||||
|
$this->computed = $this->computeData($this->getProfile());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->computed['index'];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function computeData(\Twig_Profiler_Profile $profile)
|
||||||
|
{
|
||||||
|
$data = array(
|
||||||
|
'template_count' => 0,
|
||||||
|
'block_count' => 0,
|
||||||
|
'macro_count' => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
$templates = array();
|
||||||
|
foreach ($profile as $p) {
|
||||||
|
$d = $this->computeData($p);
|
||||||
|
|
||||||
|
$data['template_count'] += ($p->isTemplate() ? 1 : 0) + $d['template_count'];
|
||||||
|
$data['block_count'] += ($p->isBlock() ? 1 : 0) + $d['block_count'];
|
||||||
|
$data['macro_count'] += ($p->isMacro() ? 1 : 0) + $d['macro_count'];
|
||||||
|
|
||||||
|
if ($p->isTemplate()) {
|
||||||
|
if (!isset($templates[$p->getTemplate()])) {
|
||||||
|
$templates[$p->getTemplate()] = 1;
|
||||||
|
} else {
|
||||||
|
$templates[$p->getTemplate()]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($d['templates'] as $template => $count) {
|
||||||
|
if (!isset($templates[$template])) {
|
||||||
|
$templates[$template] = $count;
|
||||||
|
} else {
|
||||||
|
$templates[$template] += $count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['templates'] = $templates;
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'twig';
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ class ProfilerExtension extends \Twig_Extension_Profiler
|
|||||||
private $stopwatch;
|
private $stopwatch;
|
||||||
private $events;
|
private $events;
|
||||||
|
|
||||||
public function __construct(\Twig_Profiler_Profile $profile, Stopwatch $stopwatch)
|
public function __construct(\Twig_Profiler_Profile $profile, Stopwatch $stopwatch = null)
|
||||||
{
|
{
|
||||||
parent::__construct($profile);
|
parent::__construct($profile);
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ class ProfilerExtension extends \Twig_Extension_Profiler
|
|||||||
|
|
||||||
public function enter(\Twig_Profiler_Profile $profile)
|
public function enter(\Twig_Profiler_Profile $profile)
|
||||||
{
|
{
|
||||||
if ($profile->isTemplate()) {
|
if ($this->stopwatch && $profile->isTemplate()) {
|
||||||
$this->events[$profile] = $this->stopwatch->start($profile->getName(), 'template');
|
$this->events[$profile] = $this->stopwatch->start($profile->getName(), 'template');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class ProfilerExtension extends \Twig_Extension_Profiler
|
|||||||
{
|
{
|
||||||
parent::leave($profile);
|
parent::leave($profile);
|
||||||
|
|
||||||
if ($profile->isTemplate()) {
|
if ($this->stopwatch && $profile->isTemplate()) {
|
||||||
$this->events[$profile]->stop();
|
$this->events[$profile]->stop();
|
||||||
unset($this->events[$profile]);
|
unset($this->events[$profile]);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.9",
|
"php": ">=5.3.9",
|
||||||
"symfony/security-csrf": "~2.6|~3.0.0",
|
"symfony/security-csrf": "~2.6|~3.0.0",
|
||||||
"twig/twig": "~1.17"
|
"twig/twig": "~1.18"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"symfony/finder": "~2.3|~3.0.0",
|
"symfony/finder": "~2.3|~3.0.0",
|
||||||
|
@ -63,8 +63,9 @@ class ExtensionPass implements CompilerPassInterface
|
|||||||
$container->getDefinition('twig.extension.code')->replaceArgument(0, $container->getParameter('templating.helper.code.file_link_format'));
|
$container->getDefinition('twig.extension.code')->replaceArgument(0, $container->getParameter('templating.helper.code.file_link_format'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($container->getParameter('kernel.debug') && $container->has('debug.stopwatch')) {
|
if ($container->getParameter('kernel.debug')) {
|
||||||
$container->getDefinition('twig.extension.profiler')->addTag('twig.extension');
|
$container->getDefinition('twig.extension.profiler')->addTag('twig.extension');
|
||||||
|
$container->getDefinition('twig.extension.debug')->addTag('twig.extension');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($container->has('templating')) {
|
if ($container->has('templating')) {
|
||||||
|
@ -101,10 +101,6 @@ class TwigExtension extends Extension
|
|||||||
$config['extensions']
|
$config['extensions']
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($container->getParameter('kernel.debug')) {
|
|
||||||
$loader->load('debug.xml');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($config['autoescape_service']) && isset($config['autoescape_service_method'])) {
|
if (isset($config['autoescape_service']) && isset($config['autoescape_service_method'])) {
|
||||||
$config['autoescape'] = array(new Reference($config['autoescape_service']), $config['autoescape_service_method']);
|
$config['autoescape'] = array(new Reference($config['autoescape_service']), $config['autoescape_service_method']);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<container xmlns="http://symfony.com/schema/dic/services"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
|
||||||
|
|
||||||
<parameters>
|
|
||||||
<parameter key="debug.templating.engine.twig.class">Symfony\Bundle\TwigBundle\Debug\TimedTwigEngine</parameter>
|
|
||||||
</parameters>
|
|
||||||
|
|
||||||
<services>
|
|
||||||
<service id="twig.extension.debug" class="Twig_Extension_Debug" public="false">
|
|
||||||
<tag name="twig.extension" />
|
|
||||||
</service>
|
|
||||||
</services>
|
|
||||||
</container>
|
|
@ -72,11 +72,16 @@
|
|||||||
|
|
||||||
<service id="twig.extension.profiler" class="Symfony\Bridge\Twig\Extension\ProfilerExtension" public="false">
|
<service id="twig.extension.profiler" class="Symfony\Bridge\Twig\Extension\ProfilerExtension" public="false">
|
||||||
<argument type="service" id="twig.profile" />
|
<argument type="service" id="twig.profile" />
|
||||||
<argument type="service" id="debug.stopwatch" on-invalid="ignore" />
|
<argument type="service" id="debug.stopwatch" on-invalid="null" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="twig.profile" class="Twig_Profiler_Profile" />
|
<service id="twig.profile" class="Twig_Profiler_Profile" />
|
||||||
|
|
||||||
|
<service id="data_collector.twig" class="Symfony\Bridge\Twig\DataCollector\TwigDataCollector" public="false">
|
||||||
|
<tag name="data_collector" template="@WebProfiler/Collector/twig.html.twig" id="twig" priority="255" />
|
||||||
|
<argument type="service" id="twig.profile" />
|
||||||
|
</service>
|
||||||
|
|
||||||
<service id="twig.extension.trans" class="%twig.extension.trans.class%" public="false">
|
<service id="twig.extension.trans" class="%twig.extension.trans.class%" public="false">
|
||||||
<argument type="service" id="translator" />
|
<argument type="service" id="translator" />
|
||||||
</service>
|
</service>
|
||||||
@ -128,6 +133,8 @@
|
|||||||
<argument type="service" id="twig.form.renderer" />
|
<argument type="service" id="twig.form.renderer" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service id="twig.extension.debug" class="Twig_Extension_Debug" public="false" />
|
||||||
|
|
||||||
<service id="twig.form.engine" class="%twig.form.engine.class%" public="false">
|
<service id="twig.form.engine" class="%twig.form.engine.class%" public="false">
|
||||||
<argument>%twig.form.resources%</argument>
|
<argument>%twig.form.resources%</argument>
|
||||||
</service>
|
</service>
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block toolbar %}
|
||||||
|
{% set time = collector.templatecount ? '%0.0f ms'|format(collector.time) : 'n/a' %}
|
||||||
|
{% set icon %}
|
||||||
|
<img height="28" alt="Twig" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAcCAYAAACOGPReAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAbElEQVRIx2NgGAXUBowMDAwMaWlp/6ll4KxZsxhZYJy0tDRqGMjAwMDAwEQL77OgCxSXlJBsSG9PDwqfJi6lj/fRvTJ4XYocUTBXE4q8oRtRRBnKwsw8RFw6fA0lKkd1dnYOIpfCCthRMIIAAI0IFu9Hxh7ZAAAAAElFTkSuQmCC" />
|
||||||
|
<span class="sf-toolbar-status">{{ time }}</span>
|
||||||
|
{% endset %}
|
||||||
|
{% set text %}
|
||||||
|
<div class="sf-toolbar-info-piece">
|
||||||
|
<b>Render Time</b>
|
||||||
|
<span>{{ time }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sf-toolbar-info-piece">
|
||||||
|
<b>Template Calls</b>
|
||||||
|
<span>{{ collector.templatecount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sf-toolbar-info-piece">
|
||||||
|
<b>Block Calls</b>
|
||||||
|
<span>{{ collector.blockcount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sf-toolbar-info-piece">
|
||||||
|
<b>Macro Calls</b>
|
||||||
|
<span>{{ collector.macrocount }}</span>
|
||||||
|
</div>
|
||||||
|
{% endset %}
|
||||||
|
{% include '@WebProfiler/Profiler/toolbar_item.html.twig' with { 'link': profiler_url } %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block menu %}
|
||||||
|
<span class="label">
|
||||||
|
<span class="icon"><img alt="Twig" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAgCAYAAAABtRhCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAbklEQVRIx2NgGAVDHTDCGGlpaf9pZcmsWbPg9rAgS6SlpdHCMhQ+E72DlAWbYHFJCcUG9/b0YBWnuw9HLaRPosEV4cPHh9iyBczXxGaZ0WxBfBwwM4/mw1ELRy0c4MK7s7NzCPsQvYU1CkYBNgAAV5UW+fU+ZL4AAAAASUVORK5CYII="></span>
|
||||||
|
<strong>Twig</strong>
|
||||||
|
<span class="count">
|
||||||
|
<span>{{ collector.templatecount }}</span>
|
||||||
|
<span>{{ '%0.0f ms'|format(collector.time) }}</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block panel %}
|
||||||
|
{% if collector.templatecount %}
|
||||||
|
<h2>Twig Stats</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Total Render Time<br /><small>including sub-requests rendering time</small></th>
|
||||||
|
<td><pre>{{ '%0.0f ms'|format(collector.time) }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" style="width: 30%">Template Calls</th>
|
||||||
|
<td scope="col" style="width: 60%"><pre>{{ collector.templatecount }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Block Calls</th>
|
||||||
|
<td><pre>{{ collector.blockcount }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Macro Calls</th>
|
||||||
|
<td><pre>{{ collector.macrocount }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Rendered Templates</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Template Name</th>
|
||||||
|
<th scope="col">Render Count</th>
|
||||||
|
</tr>
|
||||||
|
{% for template, count in collector.templates %}
|
||||||
|
<tr>
|
||||||
|
<td><code>{{ template }}</code></td>
|
||||||
|
<td><pre>{{ count }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Rendering Call Graph</h2>
|
||||||
|
|
||||||
|
{{ collector.htmlcallgraph }}
|
||||||
|
{% else %}
|
||||||
|
<p><em>No Twig templates were rendered for this request.</em></p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -19,7 +19,7 @@
|
|||||||
"php": ">=5.3.9",
|
"php": ">=5.3.9",
|
||||||
"symfony/http-kernel": "~2.4|~3.0.0",
|
"symfony/http-kernel": "~2.4|~3.0.0",
|
||||||
"symfony/routing": "~2.2|~3.0.0",
|
"symfony/routing": "~2.2|~3.0.0",
|
||||||
"symfony/twig-bridge": "~2.2|~3.0.0"
|
"symfony/twig-bridge": "~2.7|~3.0.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"symfony/config": "~2.2|~3.0.0",
|
"symfony/config": "~2.2|~3.0.0",
|
||||||
|
Reference in New Issue
Block a user