Redesigned the Symfony Profiler

This commit is contained in:
Javier Eguiluz 2015-08-12 16:14:36 +02:00 committed by Fabien Potencier
parent 0edcc2ef10
commit 05773c263b
42 changed files with 2570 additions and 1790 deletions

View File

@ -74,8 +74,20 @@ class TwigDataCollector extends DataCollector implements LateDataCollectorInterf
public function getHtmlCallGraph()
{
$dumper = new \Twig_Profiler_Dumper_Html();
$dump = $dumper->dump($this->getProfile());
return new \Twig_Markup($dumper->dump($this->getProfile()), 'UTF-8');
// needed to remove the hardcoded CSS styles
$dump = str_replace(array(
'<span style="background-color: #ffd">',
'<span style="color: #d44">',
'<span style="background-color: #dfd">',
), array(
'<span class="status-warning">',
'<span class="status-error">',
'<span class="status-success">',
), $dump);
return new \Twig_Markup($dump, 'UTF-8');
}
public function getProfile()

View File

@ -1,15 +1,10 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% block toolbar %}
{% set dumps_count = collector.dumpsCount %}
{% if dumps_count %}
{% if collector.dumpsCount %}
{% set icon %}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M12,22.6c-5.8,0-10.5-4.7-10.5-10.5C1.5,6.3,6.2,1.5,12,1.5s10.5,4.7,10.5,10.5C22.5,17.9,17.8,22.6,12,22.6z M12,4.5c-4.2,0-7.5,3.4-7.5,7.5c0,4.2,3.4,7.5,7.5,7.5s7.5-3.4,7.5-7.5C19.5,7.9,16.2,4.5,12,4.5z"/>
<path fill="#AAAAAA" d="M12,9.1c-0.8,0-1.5-0.7-1.5-1.5v-6c0-0.8,0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5v6C13.5,8.4,12.8,9.1,12,9.1zM13.5,22.4v-6c0-0.8-0.7-1.5-1.5-1.5s-1.5,0.7-1.5,1.5v6c0,0.8,0.7,1.5,1.5,1.5S13.5,23.2,13.5,22.4z M23.9,12c0-0.8-0.7-1.5-1.5-1.5h-6c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5h6C23.2,13.5,23.9,12.8,23.9,12z M9.1,12c0-0.8-0.7-1.5-1.5-1.5h-6c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5h6C8.4,13.5,9.1,12.8,9.1,12z"/>
</svg>
<span class="sf-toolbar-value">{{ dumps_count }}</span>
{{ include('@Debug/Profiler/icon.svg') }}
<span class="sf-toolbar-value">{{ collector.dumpsCount }}</span>
{% endset %}
{% set text %}
@ -28,6 +23,7 @@
{% endif %}
</span>
<span class="sf-toolbar-file-line">line {{ dump.line }}</span>
{{ dump.data|raw }}
</div>
{% endfor %}
@ -39,42 +35,18 @@
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon">
{{- "" -}}
<svg width="28" height="28" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve"><path fill="#3F3F3F" d="M28 13h-1.1C26.5 6.6 21.4 1.5 15 1.1V0h-2v1.1C6.6 1.5 1.5 6.6 1.1 13H0v2h1.1C1.5 21.4 6.6 26.5 13 26.9 V28h2v-1.1c6.4-0.5 11.5-5.6 11.9-11.9H28V13z M15 24.9V19h-2v5.9c-5.3-0.5-9.5-4.7-9.9-9.9H9v-2H3.1C3.5 7.7 7.7 3.5 13 3.1V9h2 V3.1c5.3 0.5 9.5 4.7 9.9 9.9H19v2h5.9C24.5 20.3 20.3 24.5 15 24.9z"/></svg>
{{- "" -}}
</span>
<strong>dump()</strong>
<span class="count">
<span>{{ collector.dumpsCount }}</span>
</span>
<span class="label {{ collector.dumpsCount == 0 ? 'disabled' }}">
<span class="icon">{{ include('@Debug/Profiler/icon.svg') }}</span>
<strong>Debug</strong>
</span>
{% endblock %}
{% block panel %}
<h2>dump()</h2>
<h2>Dumped Contents</h2>
<style>
li.sf-dump {
list-style-type: disc;
}
.sf-dump ol>li {
padding: 0;
}
.sf-dump a {
cursor: pointer;
}
.sf-dump-compact {
display: none;
}
</style>
{% if collector.dumpsCount %}
<ul class="alt">
{% for dump in collector.getDumps('html') %}
<li class="sf-dump sf-reset">
in
{% for dump in collector.getDumps('html') %}
<div class="sf-dump sf-reset">
<h3>In
{% if dump.line %}
{% set link = dump.file|file_link(dump.line) %}
{% if link %}
@ -85,19 +57,22 @@
{% else %}
{{ dump.name }}
{% endif %}
line {{ dump.line }}:
<a onclick="var s = this.nextElementSibling; if ('sf-dump-compact' == s.className) {this.innerHTML = '&#9660;'; s.className = 'sf-dump-expanded';} else {this.innerHTML = '&#9654;'; s.className = 'sf-dump-compact';}">&#9654;</a>
<span class="sf-dump-compact">
{% if dump.fileExcerpt %}{{ dump.fileExcerpt|raw }}{% else %}{{ dump.file|file_excerpt(dump.line) }}{% endif %}
</span>
<small>line {{ dump.line }}</small>
{{ dump.data|raw }}
</li>
{% endfor %}
</ul>
<a class="text-small sf-toggle" data-toggle-selector="#sf-trace-{{ loop.index0 }}" data-toggle-alt-content="Hide code">Show code</a>
</h3>
<div class="sf-dump-compact hidden" id="sf-trace-{{ loop.index0 }}">
<div class="trace">
{{ dump.fileExcerpt ? dump.fileExcerpt|raw : dump.file|file_excerpt(dump.line) }}
</div>
</div>
{{ dump.data|raw }}
</div>
{% else %}
<p>
<em>No dumped variable</em>
</p>
{% endif %}
<div class="empty">
<p>No content was dumped.</p>
</div>
{% endfor %}
{% endblock %}

View File

@ -0,0 +1,4 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M12,22.6c-5.8,0-10.5-4.7-10.5-10.5C1.5,6.3,6.2,1.5,12,1.5s10.5,4.7,10.5,10.5C22.5,17.9,17.8,22.6,12,22.6z M12,4.5c-4.2,0-7.5,3.4-7.5,7.5c0,4.2,3.4,7.5,7.5,7.5s7.5-3.4,7.5-7.5C19.5,7.9,16.2,4.5,12,4.5z"/>
<path fill="#AAAAAA" d="M12,9.1c-0.8,0-1.5-0.7-1.5-1.5v-6c0-0.8,0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5v6C13.5,8.4,12.8,9.1,12,9.1zM13.5,22.4v-6c0-0.8-0.7-1.5-1.5-1.5s-1.5,0.7-1.5,1.5v6c0,0.8,0.7,1.5,1.5,1.5S13.5,23.2,13.5,22.4z M23.9,12c0-0.8-0.7-1.5-1.5-1.5h-6c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5h6C23.2,13.5,23.9,12.8,23.9,12z M9.1,12c0-0.8-0.7-1.5-1.5-1.5h-6c-0.8,0-1.5,0.7-1.5,1.5s0.7,1.5,1.5,1.5h6C8.4,13.5,9.1,12.8,9.1,12z"/>
</svg>

After

Width:  |  Height:  |  Size: 829 B

View File

@ -0,0 +1,3 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M21,20.4V22H3v-1.6c0-3.7,2.4-6.9,5.8-8c-1.7-1.1-2.9-3-2.9-5.2c0-3.4,2.7-6.1,6.1-6.1s6.1,2.7,6.1,6.1c0,2.2-1.2,4.1-2.9,5.2C18.6,13.5,21,16.7,21,20.4z"/>
</svg>

After

Width:  |  Height:  |  Size: 345 B

View File

@ -1,5 +1,7 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% block page_title 'Security' %}
{% block toolbar %}
{% if collector.tokenClass %}
{% set is_authenticated = collector.enabled and collector.authenticated %}
@ -9,9 +11,7 @@
{% endif %}
{% set icon %}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M21,20.4V22H3v-1.6c0-3.7,2.4-6.9,5.8-8c-1.7-1.1-2.9-3-2.9-5.2c0-3.4,2.7-6.1,6.1-6.1s6.1,2.7,6.1,6.1c0,2.2-1.2,4.1-2.9,5.2C18.6,13.5,21,16.7,21,20.4z"/>
</svg>
{{ include('@Security/Collector/icon.svg') }}
<span class="sf-toolbar-value">{{ collector.user|default('n/a') }}</span>
{% endset %}
@ -21,10 +21,12 @@
<b>Logged in as</b>
<span>{{ collector.user }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Authenticated</b>
<span class="sf-toolbar-status sf-toolbar-status-{{ is_authenticated ? 'green' : 'red' }}">{{ is_authenticated ? 'Yes' : 'No' }}</span>
</div>
{% if collector.tokenClass != null %}
<div class="sf-toolbar-info-piece">
<b>Token class</b>
@ -46,54 +48,69 @@
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="42" height="30" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 42 30" enable-background="new 0 0 42 30" xml:space="preserve"><g><path fill="#3F3F3F" d="M16.1 15.3c0-0.5 0-0.8 0-1.2c0.2-0.1 0.6-0.8 0.7-1.4c0.2 0 0.4-0.2 0.5-0.8c0-0.4-0.1-0.5-0.2-0.6 c0.3-0.8 0.8-3.4-1.1-3.7C15.7 7.2 15.2 7 14.6 7c-2.6 0-2.9 2-2.4 4.2c-0.1 0.1-0.3 0.3-0.2 0.6c0.1 0.7 0.3 0.8 0.5 0.8 c0.1 0.6 0.5 1.3 0.7 1.4c0 0.4 0 0.8 0 1.2c-0.5 1.4-4 1-4.2 3.7h11.2C20.1 16.3 16.6 16.7 16.1 15.3z"/><path fill="#3F3F3F" d="M28.3 10.2c-0.2 0-0.5 0.1-0.7 0.2c-0.2 0.1-0.4 0.3-0.6 0.6c-0.2 0.3-0.4 0.6-0.5 1s-0.2 0.7-0.2 1.1 c0 0.5 0.1 0.9 0.4 1.2s0.5 0.4 0.8 0.4c0.2 0 0.4-0.1 0.7-0.2c0.2-0.1 0.5-0.3 0.7-0.6s0.4-0.6 0.5-1c0.1-0.4 0.2-0.8 0.2-1.2 c0-0.5-0.1-0.9-0.4-1.2C29 10.3 28.7 10.2 28.3 10.2z"/><path fill="#3F3F3F" d="M34 4H7C6.4 4 6 4.4 6 5v19c0 0.6 0.4 1 1 1h5v-1c-0.6 0-1-0.4-1-1c0-0.6 0.4-1 1-1h2c0.6 0 1 0.4 1 1 c0 0.6-0.4 1-1 1v1h13v-1c-0.6 0-1-0.4-1-1c0-0.6 0.4-1 1-1h2c0.6 0 1 0.4 1 1c0 0.6-0.4 1-1 1v1h5c0.6 0 1-0.4 1-1V5 C35 4.4 34.6 4 34 4z M21 19c0 0.6-0.4 1-1 1H9c-0.6 0-1-0.4-1-1V7c0-0.6 0.4-1 1-1h11c0.6 0 1 0.4 1 1V19z M32.9 16.6 c-0.5 0.4-1 0.7-1.7 1c-0.6 0.2-1.4 0.4-2.3 0.4c-0.8 0-1.6-0.1-2.3-0.3c-0.7-0.2-1.3-0.5-1.8-1c-0.5-0.4-0.9-0.9-1.1-1.5 c-0.3-0.7-0.5-1.5-0.5-2.3c0-0.9 0.2-1.8 0.6-2.6c0.5-1 1.1-1.8 2-2.4C26.5 7.3 27.6 7 28.8 7c0.9 0 1.8 0.2 2.5 0.6 c0.7 0.4 1.3 1 1.8 1.7c0.4 0.7 0.6 1.4 0.6 2.1c0 1.1-0.4 2.1-1.2 2.9c-0.7 0.8-1.4 1.2-2.3 1.2c-0.3 0-0.5 0-0.6-0.1 c-0.2-0.1-0.3-0.2-0.4-0.3c0-0.1-0.1-0.3-0.1-0.5c-0.2 0.3-0.5 0.5-0.8 0.7c-0.3 0.2-0.6 0.3-0.9 0.3c-0.3 0-0.7-0.1-1-0.3 c-0.3-0.2-0.6-0.5-0.8-0.9c-0.2-0.4-0.3-0.9-0.3-1.3c0-0.6 0.2-1.2 0.5-1.8c0.3-0.6 0.7-1.1 1.2-1.4c0.5-0.3 0.9-0.5 1.3-0.5 c0.3 0 0.6 0.1 0.9 0.3c0.3 0.2 0.6 0.4 0.8 0.8l0.2-0.9h1l-0.8 3.8c-0.1 0.5-0.2 0.8-0.2 0.9c0 0.1 0 0.2 0.1 0.3 c0.1 0.1 0.2 0.1 0.3 0.1c0.2 0 0.5-0.1 0.8-0.3c0.4-0.3 0.8-0.7 1-1.2c0.3-0.5 0.4-1 0.4-1.6c0-0.6-0.2-1.2-0.5-1.8 c-0.3-0.6-0.8-1-1.5-1.3s-1.4-0.5-2.1-0.5c-0.9 0-1.7 0.2-2.4 0.6c-0.7 0.4-1.3 1-1.7 1.8C24.2 11 24 11.9 24 12.7 c0 0.9 0.2 1.7 0.6 2.4c0.4 0.7 1 1.2 1.8 1.5c0.8 0.3 1.6 0.5 2.5 0.5c1 0 1.8-0.2 2.5-0.5c0.7-0.3 1.2-0.7 1.5-1.2h1 C33.7 15.8 33.4 16.2 32.9 16.6z"/></g></svg></span>
<strong>Security</strong>
</span>
<span class="label {{ not collector.enabled or not collector.tokenClass ? 'disabled' }}">
<span class="icon">{{ include('@Security/Collector/icon.svg') }}</span>
<strong>Security</strong>
</span>
{% endblock %}
{% block panel %}
<h2>Security</h2>
<h2>Security Token</h2>
{% if collector.tokenClass %}
<div class="metrics">
<div class="metric">
<span class="value">{{ collector.user == 'anon.' ? 'Anonymous' : collector.user }}</span>
<span class="label">Username</span>
</div>
<div class="metric">
<span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.authenticated ? 'yes' : 'no') ~ '.svg') }}</span>
<span class="label">Authenticated</span>
</div>
</div>
<table>
<tr>
<th>Username</th>
<td>{{ collector.user }}</td>
</tr>
<tr>
<th>Authenticated?</th>
<td>
{% if collector.authenticated %}
yes
{% else %}
no {% if not collector.roles|length %}<em>(probably because the user has no roles)</em>{% endif %}
{% endif %}
</td>
</tr>
<tr>
<th>Roles</th>
<td>{{ collector.roles|yaml_encode }}</td>
</tr>
{% if collector.supportsRoleHierarchy %}
<tr>
<th>Inherited Roles</th>
<td>{{ collector.inheritedRoles|yaml_encode }}</td>
</tr>
{% endif %}
{% if collector.tokenClass != null %}
<tr>
<th>Token class</th>
<td>{{ collector.tokenClass }}</td>
</tr>
{% endif %}
<thead>
<tr>
<th scope="col" class="key">Property</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
<tr>
<th>Roles</th>
<td>
{{ collector.roles is empty ? 'none' : collector.roles|yaml_encode }}
{% if not collector.authenticated and collector.roles is empty %}
<p class="help">User is not authenticated probably because they have no roles.</p>
{% endif %}
</td>
</tr>
{% if collector.supportsRoleHierarchy %}
<tr>
<th>Inherited Roles</th>
<td>{{ collector.inheritedRoles is empty ? 'none' : collector.inheritedRoles|yaml_encode }}</td>
</tr>
{% endif %}
{% if collector.tokenClass %}
<tr>
<th>Token class</th>
<td>{{ collector.tokenClass }}</td>
</tr>
{% endif %}
</tbody>
</table>
{% elseif collector.enabled %}
<p>
<em>No token</em>
</p>
<div class="empty">
<p>There is no security token.</p>
</div>
{% else %}
<p>
<em>The security component is disabled</em>
</p>
<div class="empty">
<p>The security component is disabled.</p>
</div>
{% endif %}
{% endblock %}

View File

@ -112,6 +112,7 @@ class ProfilerController
'request' => $request,
'templates' => $this->getTemplateManager()->getTemplates($profile),
'is_ajax' => $request->isXmlHttpRequest(),
'profiler_markup_version' => 2, // 1 = original profiler, 2 = Symfony 2.8+ profiler
)), 200, array('Content-Type' => 'text/html'));
}

View File

@ -19,21 +19,22 @@
{% endif %}
{% set icon %}
{% if collector.symfonyState is defined %}
{% if collector.applicationname %}
<span class="sf-toolbar-label">{{ collector.applicationname }}</span>
<span class="sf-toolbar-value">{{ collector.applicationversion }}</span>
{% elseif collector.symfonyState is defined %}
<span class="sf-toolbar-label">
{{ include('@WebProfiler/Icon/symfony.svg') }}
</span>
<span class="sf-toolbar-value">{{ collector.symfonyversion }}</span>
{% elseif collector.applicationname %}
<span class="sf-toolbar-label">{{ collector.applicationname }}</span>
<span class="sf-toolbar-value">{{ collector.applicationversion }}</span>
{% endif %}
{% endset %}
{% set text %}
{% if collector.applicationname %}
<div class="sf-toolbar-info-piece">
{{ collector.applicationname }} <b>{{ collector.applicationversion }}</b>
<b>{{ collector.applicationname }}</b>
<span>{{ collector.applicationversion }}</span>
</div>
{% endif %}
@ -88,118 +89,149 @@
<span>{{ collector.sapiName }}</span>
</div>
{% if collector.symfonyversion is defined %}
<div class="sf-toolbar-info-piece">
<b>Resources</b>
<span>
<a href="https://symfony.com/doc/{{ collector.symfonyversion }}/index.html" rel="help">
Read Symfony {{ collector.symfonyversion }} Docs
</a>
{% if 'Silex' == collector.applicationname %}
<a href="http://silex.sensiolabs.org/documentation" rel="help">
Read Silex Docs
</a>
{% else %}
<a href="https://symfony.com/doc/{{ collector.symfonyversion }}/index.html" rel="help">
Read Symfony {{ collector.symfonyversion }} Docs
</a>
{% endif %}
</span>
</div>
{% endif %}
{% endset %}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false, status: block_status }) }}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: true, name: 'config', status: block_status }) }}
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="21" height="28" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 21 28" enable-background="new 0 0 21 28" xml:space="preserve"><g><path fill="#3F3F3F" d="M5 17H1c-0.5 0-1-0.4-1-1V9c0-0.5 0.4-1 1-1h4c0.5 0 1 0.4 1 1v7C6 16.6 5.6 17 5 17z"/><path fill="#3F3F3F" d="M19 17h-4c-0.5 0-1-0.4-1-1V9c0-0.5 0.4-1 1-1h4c0.5 0 1 0.4 1 1v7C20 16.6 19.6 17 19 17z"/><path fill="#3F3F3F" d="M12.1 20h-4c-0.5 0-1-0.4-1-1v-7c0-0.5 0.4-1 1-1h4c0.5 0 1 0.4 1 1v7C13.1 19.5 12.6 20 12.1 20z"/><rect x="9.1" y="5.8" fill="#3F3F3F" width="2" height="4.5"/><rect x="16" y="17.7" fill="#3F3F3F" width="2" height="4.5"/><rect x="2.1" y="17.7" fill="#3F3F3F" width="2" height="4.5"/><rect x="9.1" y="20.7" fill="#3F3F3F" width="2" height="1.5"/><rect x="2.1" y="5.7" fill="#3F3F3F" width="2" height="1.5"/><rect x="16.1" y="5.7" fill="#3F3F3F" width="2" height="1.5"/></g></svg></span>
<strong>Config</strong>
</span>
<span class="label label-status-{{ collector.symfonyState == 'eol' ? 'red' : collector.symfonyState in ['eom', 'dev'] ? 'yellow' : '' }}">
<span class="icon">{{ include('@WebProfiler/Icon/config.svg') }}</span>
<strong>Configuration</strong>
</span>
{% endblock %}
{% block panel %}
<h2>Project Configuration</h2>
<table>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr>
{% if collector.applicationname %}
<th>Application</th>
<td>{{ collector.applicationname }} {{ collector.applicationversion }} (on Symfony {{ collector.symfonyversion }})</td>
{% else %}
<th>Symfony version</th>
<td>{{ collector.symfonyversion }}</td>
{% endif %}
</tr>
{% if 'n/a' != collector.appname %}
<tr>
<th>Application name</th>
<td>{{ collector.appname }}</td>
</tr>
{% endif %}
{% if 'n/a' != collector.env %}
<tr>
<th>Environment</th>
<td>{{ collector.env }}</td>
</tr>
{% endif %}
{% if 'n/a' != collector.debug %}
<tr>
<th>Debug</th>
<td>{{ collector.debug ? 'enabled' : 'disabled' }}</td>
</tr>
{% endif %}
</table>
{% if collector.applicationname %}
{# this application is not the Symfony framework #}
<h2>Project Configuration</h2>
<h2>PHP configuration</h2>
<table>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr>
<th>PHP version</th>
<td>{{ collector.phpversion }}</td>
</tr>
<tr>
<th>Xdebug</th>
<td>{{ collector.hasxdebug ? 'enabled' : 'disabled' }}</td>
</tr>
<tr>
<th>PHP acceleration</th>
<td>{{ collector.hasaccelerator ? 'enabled' : 'disabled' }}</td>
</tr>
<tr>
<th>XCache</th>
<td>{{ collector.hasxcache ? 'enabled' : 'disabled' }}</td>
</tr>
<tr>
<th>APC</th>
<td>{{ collector.hasapc ? 'enabled' : 'disabled' }}</td>
</tr>
<tr>
<th>Zend OPcache</th>
<td>{{ collector.haszendopcache ? 'enabled' : 'disabled' }}</td>
</tr>
<tr>
<th>EAccelerator</th>
<td>{{ collector.haseaccelerator ? 'enabled' : 'disabled' }}</td>
</tr>
<tr>
<th>Full PHP configuration</th>
<td><a href="{{ path('_profiler_phpinfo') }}"><code>phpinfo</code></a></td>
</tr>
</table>
<div class="metrics">
<div class="metric">
<span class="value">{{ collector.applicationname }}</span>
<span class="label">Application name</span>
</div>
<div class="metric">
<span class="value">{{ collector.applicationversion }}</span>
<span class="label">Application version</span>
</div>
</div>
<p>
Based on <a class="text-bold" href="https://symfony.com">Symfony {{ collector.symfonyversion }}</a>
</p>
{% else %}
<h2>Symfony Configuration</h2>
<div class="metrics">
<div class="metric">
<span class="value">{{ collector.symfonyversion }}</span>
<span class="label">Symfony version</span>
</div>
{% if 'n/a' != collector.appname %}
<div class="metric">
<span class="value">{{ collector.appname }}</span>
<span class="label">Application name</span>
</div>
{% endif %}
{% if 'n/a' != collector.env %}
<div class="metric">
<span class="value">{{ collector.env }}</span>
<span class="label">Environment</span>
</div>
{% endif %}
{% if 'n/a' != collector.debug %}
<div class="metric">
<span class="value">{{ collector.debug ? 'enabled' : 'disabled' }}</span>
<span class="label">Debug</span>
</div>
{% endif %}
</div>
{% endif %}
<h2>PHP Configuration</h2>
<div class="metrics">
<div class="metric">
<span class="value">{{ collector.phpversion }}</span>
<span class="label">PHP version</span>
</div>
<div class="metric">
<span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.hasaccelerator ? 'yes' : 'no') ~ '.svg') }}</span>
<span class="label">PHP acceleration</span>
</div>
<div class="metric">
<span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.hasxdebug ? 'yes' : 'no') ~ '.svg') }}</span>
<span class="label">Xdebug</span>
</div>
</div>
<div class="metrics metrics-horizontal">
<div class="metric">
<span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.haszendopcache ? 'yes' : 'no') ~ '.svg') }}</span>
<span class="label">OPcache</span>
</div>
<div class="metric">
<span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.hasapc ? 'yes' : 'no') ~ '.svg') }}</span>
<span class="label">APC</span>
</div>
<div class="metric">
<span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.hasxcache ? 'yes' : 'no') ~ '.svg') }}</span>
<span class="label">XCache</span>
</div>
<div class="metric">
<span class="value">{{ include('@WebProfiler/Icon/' ~ (collector.haseaccelerator ? 'yes' : 'no') ~ '.svg') }}</span>
<span class="label">EAccelerator</span>
</div>
</div>
<p>
<a href="{{ path('_profiler_phpinfo') }}">View full PHP configuration</a>
</p>
{% if collector.bundles %}
<h2>Active bundles</h2>
<h2>Enabled Bundles <small>({{ collector.bundles|length }})</small></h2>
<table>
<tr>
<th>Name</th>
<th>Path</th>
</tr>
{% set bundles = collector.bundles %}
{% for name in bundles|keys|sort %}
<tr>
<th>{{ name }}</th>
<td>{{ bundles[name] }}</td>
</tr>
{% endfor %}
<thead>
<tr>
<th class="key">Name</th>
<th>Path</th>
</tr>
</thead>
<tbody>
{% for name in collector.bundles|keys|sort %}
<tr>
<th scope="row" class="font-normal">{{ name }}</th>
<td class="font-normal">{{ collector.bundles[name] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endblock %}

View File

@ -1,79 +1,117 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% from _self import display_listener %}
{% import _self as helper %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="26" height="34" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 26 34" enable-background="new 0 0 26 34" xml:space="preserve"><g><path fill="#3F3F3F" d="M15.5 14.8c0.5-0.6 0.9-1.4 0.9-2.3c0-1.9-1.5-3.4-3.4-3.4s-3.4 1.5-3.4 3.4c0 0.9 0.3 1.7 0.9 2.3L3.2 34 h2.5l0.4-1.1l6.8-4.3l6.8 4.3l0.4 1.1h2.5L15.5 14.8z M16 22.6l-2.1-1l1.4-0.7L16 22.6z M13 16c0.1 0 0.3 0 0.4 0l1.6 4.2l-2 1 l-2-1l1.6-4.2C12.7 15.9 12.9 16 13 16z M12.1 21.6l-2.1 1l0.6-1.7L12.1 21.6z M7 30.7L8.8 26l2.9 1.8L7 30.7z M9.3 24.7l0.4-1 L13 22l3.4 1.7l0.4 1L13 27L9.3 24.7z M14.3 27.8l2.9-1.8l1.8 4.7L14.3 27.8z"/><g><path fill="#3F3F3F" d="M6.2 6.2c0.7-0.7 1.7-1.1 2.7-1.1v1.3c-0.7 0-1.3 0.2-1.8 0.7S6.4 8.2 6.4 8.9H5.1 C5.1 7.9 5.5 6.9 6.2 6.2z"/><path fill="#3F3F3F" d="M2.5 8.9c0-1.7 0.7-3.3 1.9-4.5s2.8-1.9 4.5-1.9l0 1.3c-1.4 0-2.6 0.5-3.6 1.5S3.8 7.5 3.8 8.9 C3.8 8.9 2.5 8.9 2.5 8.9z"/><path fill="#3F3F3F" d="M5.6 0.7C6.6 0.2 7.7 0 8.9 0l0 0v1.3c-2 0-4 0.8-5.4 2.2S1.3 6.9 1.3 8.9H0c0-1.2 0.2-2.3 0.7-3.3 c0.4-1.1 1.1-2.1 2-2.9S4.4 1.1 5.6 0.7L5.6 0.7z"/></g><g><path fill="#3F3F3F" d="M20.9 8.9h-1.3c0-0.7-0.2-1.3-0.7-1.8c-0.5-0.5-1.1-0.7-1.8-0.7V5.1c1 0 2 0.4 2.7 1.1 C20.5 6.9 20.9 7.9 20.9 8.9z"/><path fill="#3F3F3F" d="M22.2 8.9c0-1.4-0.5-2.6-1.5-3.6c-1-1-2.2-1.5-3.6-1.5V2.5c1.7 0 3.3 0.7 4.5 1.9s1.9 2.8 1.9 4.5 C23.5 8.9 22.2 8.9 22.2 8.9z"/><path fill="#3F3F3F" d="M20.5 0.7c1.1 0.4 2.1 1.1 2.9 2s1.5 1.8 2 2.9C25.8 6.6 26 7.7 26 8.9h-1.3c0-2-0.8-4-2.2-5.4 s-3.4-2.2-5.4-2.2V0l0 0C18.3 0 19.4 0.2 20.5 0.7L20.5 0.7z"/></g></g></svg></span>
<span class="icon">{{ include('@WebProfiler/Icon/event.svg') }}</span>
<strong>Events</strong>
</span>
{% endblock %}
{% block panel %}
{% if collector.calledlisteners|length %}
{{ block('panelContent') }}
<h2>Event Dispatcher</h2>
{% if collector.calledlisteners is empty %}
<div class="empty">
<p>No events have been recorded. Check that debugging is enabled in the kernel.</p>
</div>
{% else %}
<h2>Events</h2>
<p>
<em>No events have been recorded. Are you sure that debugging is enabled in the kernel?</em>
</p>
<div class="sf-tabs">
<div class="tab">
<h3 class="tab-title">Called Listeners <span class="badge">{{ collector.calledlisteners|length }}</span></h3>
<div class="tab-content">
{{ helper.render_table(collector.calledlisteners) }}
</div>
</div>
<div class="tab">
<h3 class="tab-title">Not Called Listeners <span class="badge">{{ collector.notcalledlisteners|length }}</span></h3>
<div class="tab-content">
{% if collector.notcalledlisteners is empty %}
<div class="empty">
<p>
<strong>There are no uncalled listeners</strong>.
</p>
<p>
All listeners were called for this request or an error occurred
when trying to collect uncalled listeners (in which case check the
logs to get more information).
</p>
</div>
{% else %}
{{ helper.render_table(collector.notcalledlisteners) }}
{% endif %}
</div>
</div>
</div>
{% endif %}
{% endblock %}
{% block panelContent %}
<h2>Called Listeners</h2>
{% macro render_table(listeners) %}
<table>
<tr>
<th>Event name</th>
<th>Listener</th>
</tr>
{% for listener in collector.calledlisteners %}
<thead>
<tr>
<td><code>{{ listener.event }}</code></td>
<td><code>{{ display_listener(listener) }}</code></td>
</tr>
{% endfor %}
</table>
<h2>Not Called Listeners</h2>
{% if collector.notcalledlisteners %}
<table>
<tr>
<th>Event name</th>
<th class="text-right">Priority</th>
<th>Listener</th>
</tr>
{% set listeners = collector.notcalledlisteners %}
{% for listener in listeners|keys|sort %}
<tr>
<td><code>{{ listeners[listener].event }}</code></td>
<td><code>{{ display_listener(listeners[listener]) }}</code></td>
</tr>
{% endfor %}
</table>
{% else %}
<p>
<strong>No uncalled listeners</strong>.
</p>
<p>
</thead>
All listeners were called for this request or an error occurred
when trying to collect uncalled listeners (in which case check the
logs to get more information).
{% set previous_event = (listeners|first).event %}
{% for listener in listeners %}
{% if loop.first or listener.event != previous_event %}
{% if not loop.first %}
</tbody>
{% endif %}
</p>
{% endif %}
{% endblock %}
<tbody>
<tr>
<th colspan="2" class="colored font-normal">{{ listener.event }}</th>
</tr>
{% macro display_listener(listener) %}
{% if listener.type == "Closure" %}
Closure
{% elseif listener.type == "Function" %}
{% set link = listener.file|file_link(listener.line) %}
{% if link %}<a href="{{ link }}">{{ listener.function }}</a>{% else %}{{ listener.function }}{% endif %}
{% elseif listener.type == "Method" %}
{% set link = listener.file|file_link(listener.line) %}
{{ listener.class|abbr_class }}::{% if link %}<a href="{{ link }}">{{ listener.method }}</a>{% else %}{{ listener.method }}{% endif %}
{% endif %}
{% set previous_event = listener.event %}
{% endif %}
<tr>
<td class="text-right">{{ listener.priority|default('-') }}</td>
<td class="font-normal">
{% if listener.type == 'Closure' %}
Closure
<span class="text-muted text-small">(there is no class or file information)</span>
{% elseif listener.type == 'Function' %}
{% set link = listener.file|file_link(listener.line) %}
{% if link %}
<a href="{{ link }}">{{ listener.function }}()</a>
<span class="text-muted text-small">({{ listener.file }})</span>
{% else %}
{{ listener.function }}()
<span class="text-muted newline text-small">{{ listener.file }} (line {{ listener.line }})</span>
{% endif %}
{% elseif listener.type == "Method" %}
{% set link = listener.file|file_link(listener.line) %}
{% set class_namespace = listener.class|split('\\', -1)|join('\\') %}
{% if link %}
<a href="{{ link }}"><strong>{{ listener.class|abbr_class|striptags }}</strong>::{{ listener.method }}()</a>
<span class="text-muted text-small">({{ listener.class }})</span>
{% else %}
<span>{{ class_namespace }}\</span><strong>{{ listener.class|abbr_class|striptags }}</strong>::{{ listener.method }}()
<span class="text-muted newline text-small">{{ listener.file }} (line {{ listener.line }})</span>
{% endif %}
{% endif %}
</td>
</tr>
{% if loop.last %}
</tbody>
{% endif %}
{% endfor %}
</table>
{% endmacro %}

View File

@ -1,55 +1,82 @@
.sf-reset .traces {
padding-bottom: 14px;
padding: 0 0 1em 1.5em;
}
.sf-reset .traces a {
font-size: 14px;
}
.sf-reset .traces abbr {
border-bottom-color: #AAA;
padding-bottom: 2px;
}
.sf-reset .traces li {
font-size: 12px;
color: #868686;
padding: 5px 4px;
ccolor: #222;
font-size: 14px;
padding: 5px 0;
list-style-type: decimal;
margin-left: 20px;
margin: 0 0 0 1em;
white-space: break-word;
}
.sf-reset .traces li.selected {
background: rgba(255, 255, 153, 0.5);
}
.sf-reset .traces ol li {
font-size: 12px;
color: #777;
}
.sf-reset #logs .traces li.error {
font-style: normal;
color: #AA3333;
background: #f9ecec;
}
.sf-reset #logs .traces li.warning {
font-style: normal;
background: #ffcc00;
}
/* fix for Opera not liking empty <li> */
.sf-reset .traces li:after {
content: "\00A0";
background: #FFCC00;
}
.sf-reset .trace {
border: 1px solid #D3D3D3;
border: 1px solid #DDD;
background: #FFF;
padding: 10px;
overflow: auto;
margin: 10px 0 20px;
margin: 1em 0;
}
.sf-reset .trace code,
#traces-text pre {
font-size: 13px;
}
.sf-reset .block-exception {
border-radius: 16px;
margin-bottom: 20px;
background-color: #f6f6f6;
border: 1px solid #dfdfdf;
padding: 30px 28px;
margin-bottom: 2em;
background-color: #FFF;
border: 1px solid #EEE;
padding: 28px;
word-wrap: break-word;
overflow: hidden;
}
.sf-reset .block-exception h1 {
font-size: 21px;
font-weight: normal;
margin: 0 0 12px;
}
.sf-reset .block-exception .linked {
margin-top: 1em;
}
.sf-reset .block {
margin-bottom: 2em;
}
.sf-reset .block h2 {
font-size: 16px;
}
.sf-reset .block-exception div {
color: #313131;
font-size: 10px;
font-size: 14px;
}
.sf-reset .block-exception-detected .illustration-exception,
.sf-reset .block-exception-detected .text-exception {
float: left;
}
.sf-reset .block-exception-detected .illustration-exception {
width: 152px;
width: 110px;
}
.sf-reset .block-exception-detected .text-exception {
width: 670px;
width: 650px;
margin-left: 20px;
padding: 30px 44px 24px 46px;
position: relative;
}
@ -65,40 +92,6 @@
bottom: 0;
right: 50px;
}
.sf-reset .block-exception p {
font-family: Arial, Helvetica, sans-serif;
}
.sf-reset .block-exception p a,
.sf-reset .block-exception p a:hover {
color: #565656;
}
.sf-reset .logs h2 {
float: left;
width: 654px;
}
.sf-reset .error-count {
float: right;
width: 170px;
text-align: right;
}
.sf-reset .error-count span {
display: inline-block;
background-color: #aacd4e;
border-radius: 6px;
padding: 4px;
color: white;
margin-right: 2px;
font-size: 11px;
font-weight: bold;
}
.sf-reset .toggle {
vertical-align: middle;
}
.sf-reset .linked ul,
.sf-reset .linked li {
display: inline;
}
.sf-reset #output-content {
color: #000;
font-size: 12px;
}

View File

@ -3,34 +3,34 @@
{% block head %}
{% if collector.hasexception %}
<style>
{{ render(path('_profiler_exception_css', { 'token': token })) }}
{{ render(path('_profiler_exception_css', { token: token })) }}
</style>
{% endif %}
{{ parent() }}
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="42" height="30" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 42 30" enable-background="new 0 0 42 30" xml:space="preserve"><path fill="#3F3F3F" d="M41 10.9c-0.3-0.5-1-0.9-1.5-0.7c-0.9 0.3-1.2 1.7-2.1 1.7c-0.1-0.3 0-0.7 0.1-0.9c0.2-0.3 0.4-0.5 0.5-0.8 c0.3-0.6 0.2-1.3-0.1-1.8c-0.4-0.6-1.3-0.9-1.9-0.6c-0.7 0.3-1.1 1.1-0.8 1.8c0.2 0.5 0.7 0.9 0.9 1.4c0.1 0.3 0 0.8-0.3 0.9 c-0.3 0.1-0.5-0.2-0.8-0.3c-0.3-0.2-0.7-0.1-1 0.1s-0.4 0.6-0.3 0.9c0.2 0.4 0.7 0.6 1.1 0.6s0.9-0.1 1.4 0c0.1 0.4 0 0.8-0.2 1.1 c-0.2 0.3-0.6 0.5-0.9 0.7c-0.6 0.4-1.3 0.7-2 0.9v-3.5v-0.8v-1C33 4.8 28.2 0 22.4 0h-2.8C13.8 0 9 4.8 9 10.6v1v0.8V16 c-0.7-0.2-1.4-0.5-2-0.9c-0.3-0.2-0.7-0.4-0.9-0.7c-0.2-0.3-0.4-0.7-0.2-1.1c0.5-0.1 0.9 0 1.4 0s1-0.2 1.1-0.6 c0.1-0.3 0-0.7-0.3-0.9s-0.7-0.2-1-0.1c-0.2 0.1-0.5 0.3-0.8 0.3C5.9 11.8 5.8 11.3 6 11c0.2-0.5 0.7-0.9 0.9-1.4 c0.3-0.7-0.1-1.5-0.8-1.8c-0.7-0.3-1.5 0-1.9 0.6C3.8 8.9 3.7 9.6 4 10.2c0.1 0.3 0.4 0.5 0.5 0.8c0.2 0.3 0.3 0.6 0.1 0.9 c-0.9 0-1.3-1.4-2.1-1.7C2 10.1 1.3 10.4 1 10.9s-0.2 1.2 0.1 1.8c0.1 0.2 0.3 0.4 0.6 0.6c0.7 0.4 1.6 0 2.4-0.4 c0.1 0 0.2-0.1 0.3-0.1c0.2 0.1 0.2 0.4 0.2 0.6c-0.1 0.7-0.1 1.5 0.1 2.1c0.4 0.9 1.2 1.6 2.1 2C7.5 17.8 8.2 18 9 18.1v6.1 c0 2.1 1.7 3.8 3.8 3.8h0.5c2.1 0 3.8-1.7 3.8-3.8c0 2.1 1.7 3.8 3.8 3.8h0.5c2.1 0 3.8-1.7 3.8-3.8c0 2.1 1.7 3.8 3.8 3.8h0.5 c2.1 0 3.8-1.7 3.8-3.8v-6.1c0.8-0.1 1.5-0.3 2.3-0.6c0.9-0.4 1.7-1.1 2.1-2c0.3-0.7 0.3-1.4 0.1-2.1c0-0.2-0.1-0.6 0.2-0.6 c0.1 0 0.2 0 0.3 0.1c0.7 0.4 1.6 0.8 2.4 0.4c0.2-0.1 0.4-0.3 0.6-0.6C41.2 12.2 41.3 11.5 41 10.9z M12 8.5C12 6.1 13.6 4 15.7 4 s3.7 2 3.7 4.5c0 1.7-0.8 3.2-2 4c0.4-0.4 0.6-0.8 0.6-1.4c0-1.1-0.9-2-2-2s-2 0.9-2 2c0 1 0.7 1.8 1.7 1.9c0 0 0 0 0 0 C13.6 13 12 11 12 8.5z M21 21c-3.3 0-5.9-1.8-6-4.1c0-0.3 0.2-0.6 0.6-0.6c0.4-0.1 0.7 0.1 0.8 0.5l0-0.1c0.5 1.6 2.4 2.8 4.6 2.8 c2.3 0 4.1-1.2 4.6-2.9l0 0.1c0.1-0.3 0.4-0.5 0.8-0.5c0.3 0 0.5 0.2 0.6 0.4c0 0.1 0 0.1 0 0.2C27 19.2 24.3 21 21 21z M26.3 13 C26.3 13 26.3 13 26.3 13c0.9-0.1 1.6-1 1.6-1.9c0-1.1-0.9-2-2-2s-2 0.9-2 2c0 0.5 0.2 1 0.6 1.4c-1.2-0.8-2-2.2-2-4 c0-2.5 1.6-4.5 3.7-4.5s3.7 2 3.7 4.5C30 11 28.4 13 26.3 13z"/></svg></span>
<strong>Exception</strong>
<span class="count">
<span class="label {{ collector.hasexception ? 'label-status-error' : 'disabled' }}">
<span class="icon">{{ include('@WebProfiler/Icon/exception.svg') }}</span>
<strong>Exception</strong>
{% if collector.hasexception %}
<span>1</span>
<span class="count">
<span>1</span>
</span>
{% endif %}
</span>
</span>
{% endblock %}
{% block panel %}
<h2>Exception</h2>
<h2>Exceptions</h2>
{% if not collector.hasexception %}
<p>
<em>No exception was thrown and uncaught during the request.</em>
</p>
<div class="empty">
<p>No exception was thrown and caught during the request.</p>
</div>
{% else %}
<div class="sf-reset">
{{ render(path('_profiler_exception', { 'token': token })) }}
{{ render(path('_profiler_exception', { token: token })) }}
</div>
{% endif %}
{% endblock %}

View File

@ -8,11 +8,7 @@
{% set icon %}
{{ include('@WebProfiler/Icon/form.svg') }}
<span class="sf-toolbar-value">
{% if collector.data.nb_errors %}
{{ collector.data.nb_errors }}
{% else %}
{{ collector.data.forms|length }}
{% endif %}
{{ collector.data.nb_errors ?: collector.data.forms|length }}
</span>
{% endset %}
@ -32,188 +28,184 @@
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="20" height="27" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 20 27" enable-background="new 0 0 20 27" xml:space="preserve"><g><polygon fill="#3F3F3F" points="16,2 13,2 13,0 7,0 7,2 4,2 4,6 16,6"/><path fill="#3F3F3F" d="M17 3v4H3V3H0v24h20V3H17z M3 13h10v1H3V13z M8 24H3v-1h5V24z M17 22H3v-1h14V22z M17 20H3v-1h14V20z M17 18H3v-1h14V18z M17 16H4v-1h13V16z M17 12H3v-1h14V12z M17 10H4V9h13V10z"/></g></svg></span>
<span class="label label-status-{{ collector.data.nb_errors ? 'error' }} {{ collector.data.forms is empty ? 'disabled' }}">
<span class="icon">{{ include('@WebProfiler/Icon/form.svg') }}</span>
<strong>Forms</strong>
{% if collector.data.forms|length %}
<span class="count"><span>{{ collector.data.forms|length }}</span></span>
{% if collector.data.nb_errors > 0 %}
<span class="count">
<span>{{ collector.data.nb_errors }}</span>
</span>
{% endif %}
</span>
{% endblock %}
{% block panel %}
<style type="text/css">
.window {
/*background: #F6F6F6;*/
margin: -30px -40px -40px;
}
.toggle-icon {
display: inline-block;
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgBAMAAADpp+X/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDgwx4LcKwAAAABVQTFRFAAAA////////////////ZmZm////bvjBwAAAAAV0Uk5TABZwsuCVEUjgAAAAAWJLR0QF+G/pxwAAAE1JREFUGNNjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBmwgTQgQGWgA7h2uIFwK+CWwp1BpHvYEqDuATEYkBlY3IOmBq6dCPcAAIT5Eg2IksjQAAAAAElFTkSuQmCC") no-repeat top left #5eb5e0;
}
.closed .toggle-icon, .closed.toggle-icon {
background-position: bottom left;
}
.toggle-icon.empty {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAZgBmAGYHukptAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhIf6CA40AAAAFRJREFUOMvtk7ENACEMA61vfx767MROWfO+AdGBHlNyTZrYUZRYDBII4NWE1pNdpFarfgLUbpDaBEgBYRiEVjsvDLa1l6O4Z3wkFWN+OfLKdpisOH/TlICzukmUJwAAAABJRU5ErkJggg==");
}
.tree {
width: 230px;
padding: 10px;
font-size: 12px;
float: left;
}
#content .tree h2 {
font-size: 13px;
padding: 5px 7px;
margin: 0;
}
.tree li {
margin: 0;
padding: 0;
width: 100%;
}
.tree .tree-inner {
width: 100%;
padding: 5px 7px 5px 22px;
border-radius: 6px;
color: #313131;
cursor: pointer;
position: relative;
{% block head %}
{{ parent() }}
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.tree a {
text-decoration: none;
}
.tree .toggle-button {
/* provide a bigger clickable area than just 10x10px */
width: 16px;
height: 16px;
/* vertically center the button */
position: absolute;
top: 50%;
margin-top: -8px;
margin-left: -18px;
}
.tree .toggle-icon {
width: 10px;
height: 10px;
/* position the icon in the center of the clickable area */
margin-left: 3px;
margin-top: 3px;
background-size: 10px 20px;
background-color: #ccc;
}
.tree .toggle-icon.empty {
width: 10px;
height: 10px;
position: absolute;
top: 50%;
margin-top: -5px;
margin-left: -15px;
background-size: 10px 10px;
}
.tree ul ul .tree-inner {
padding-left: 37px;
}
.tree ul ul ul .tree-inner {
padding-left: 52px;
}
.tree ul ul ul ul .tree-inner {
padding-left: 67px;
}
.tree ul ul ul ul ul .tree-inner {
padding-left: 82px;
}
.tree .tree-inner:hover {
background: #dfdfdf;
}
.tree .tree-inner.active, .tree .tree-inner.active:hover {
background: #dfdfdf;
font-weight: bold;
color: #313131;
}
.tree .tree-inner.active .toggle-icon, .tree .tree-inner:hover .toggle-icon, .tree .tree-inner.active:hover .toggle-icon {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgBAMAAADpp+X/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhEYXWn+sAAAABhQTFRFAAAA39/f39/f39/f39/fZmZm39/f////gc3YPwAAAAV0Uk5TAAtAc6ZeVyCYAAAAAWJLR0QF+G/pxwAAAE1JREFUGNNjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBmwgXIgQGWgA7h2uIFwK+CWwp1BpHvYC6DuATEYkBlY3IOmBq6dCPcAADqLE4MnBi/fAAAAAElFTkSuQmCC");
background-color: #aaa;
}
.tree .tree-inner.active .toggle-icon.empty, .tree .tree-inner:hover .toggle-icon.empty, .tree .tree-inner.active:hover .toggle-icon.empty {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhoucSey4gAAABVQTFRFAAAA39/f39/f39/f39/fZmZm39/fD5Dx2AAAAAV0Uk5TAAtAc6ZeVyCYAAAAAWJLR0QF+G/pxwAAADJJREFUCNdjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBnIA3DtcAPhVsAthTkDAFOfBKW9C1iqAAAAAElFTkSuQmCC");
}
.tree-details {
border-left: 1px solid #dfdfdf;
background: white;
margin-left: 250px;
padding: 30px 40px 40px;
}
.tree-details h3 {
position: relative;
}
.tree-details .toggle-icon {
width: 16px;
height: 16px;
/* vertically center the button */
position: absolute;
top: 50%;
margin-top: -9px;
margin-left: 6px;
}
.form-type {
color: #999999;
}
.hidden {
display: none;
}
.badge-error {
float: right;
background: #a33;
color: #fff;
padding: 1px 4px;
font-size: 10px;
font-weight: bold;
vertical-align: middle;
border-radius: 6px;
}
.errors h3 {
color: #800;
}
.errors th, .errors td {
border-color: #800;
}
.errors th {
background: #a33;
color: #fff;
}
.errors .toggle-icon {
background-color: #a33;
}
h3 a, h3 a:hover, h3 a:focus {
color: inherit;
text-decoration: inherit;
}
<style>
#tree-menu {
float: left;
padding-right: 10px;
width: 230px;
}
#tree-menu ul {
list-style: none;
margin: 0;
padding-left: 0;
}
#tree-menu li {
margin: 0;
padding: 0;
width: 100%;
}
#tree-menu .empty {
border: 0;
mmargin: 0;
padding: 0;
}
#tree-details-container {
border-left: 1px solid #DDD;
margin-left: 250px;
padding-left: 20px;
}
.tree-details {
padding-bottom: 40px;
}
.tree-details h3 {
font-size: 18px;
position: relative;
}
.toggle-icon {
display: inline-block;
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgBAMAAADpp+X/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDgwx4LcKwAAAABVQTFRFAAAA////////////////ZmZm////bvjBwAAAAAV0Uk5TABZwsuCVEUjgAAAAAWJLR0QF+G/pxwAAAE1JREFUGNNjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBmwgTQgQGWgA7h2uIFwK+CWwp1BpHvYEqDuATEYkBlY3IOmBq6dCPcAAIT5Eg2IksjQAAAAAElFTkSuQmCC") no-repeat top left #5eb5e0;
}
.closed .toggle-icon, .closed.toggle-icon {
background-position: bottom left;
}
.toggle-icon.empty {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAZgBmAGYHukptAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhIf6CA40AAAAFRJREFUOMvtk7ENACEMA61vfx767MROWfO+AdGBHlNyTZrYUZRYDBII4NWE1pNdpFarfgLUbpDaBEgBYRiEVjsvDLa1l6O4Z3wkFWN+OfLKdpisOH/TlICzukmUJwAAAABJRU5ErkJggg==");
}
.tree .tree-inner {
cursor: pointer;
padding: 5px 7px 5px 22px;
position: relative;
}
.tree .toggle-button {
/* provide a bigger clickable area than just 10x10px */
width: 16px;
height: 16px;
/* vertically center the button */
position: absolute;
top: 50%;
margin-top: -8px;
margin-left: -18px;
}
.tree .toggle-icon {
width: 10px;
height: 10px;
/* position the icon in the center of the clickable area */
margin-left: 3px;
margin-top: 3px;
background-size: 10px 20px;
background-color: #ccc;
}
.tree .toggle-icon.empty {
width: 10px;
height: 10px;
position: absolute;
top: 50%;
margin-top: -5px;
margin-left: -15px;
background-size: 10px 10px;
}
.tree ul ul .tree-inner {
padding-left: 37px;
}
.tree ul ul ul .tree-inner {
padding-left: 52px;
}
.tree ul ul ul ul .tree-inner {
padding-left: 67px;
}
.tree ul ul ul ul ul .tree-inner {
padding-left: 82px;
}
.tree .tree-inner:hover {
background: #dfdfdf;
}
.tree .tree-inner.active, .tree .tree-inner.active:hover {
background: #E0E0E0;
font-weight: bold;
}
.tree .tree-inner.active .toggle-icon, .tree .tree-inner:hover .toggle-icon, .tree .tree-inner.active:hover .toggle-icon {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgBAMAAADpp+X/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhEYXWn+sAAAABhQTFRFAAAA39/f39/f39/f39/fZmZm39/f////gc3YPwAAAAV0Uk5TAAtAc6ZeVyCYAAAAAWJLR0QF+G/pxwAAAE1JREFUGNNjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBmwgXIgQGWgA7h2uIFwK+CWwp1BpHvYC6DuATEYkBlY3IOmBq6dCPcAADqLE4MnBi/fAAAAAElFTkSuQmCC");
background-color: #999;
}
.tree .tree-inner.active .toggle-icon.empty, .tree .tree-inner:hover .toggle-icon.empty, .tree .tree-inner.active:hover .toggle-icon.empty {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhoucSey4gAAABVQTFRFAAAA39/f39/f39/f39/fZmZm39/fD5Dx2AAAAAV0Uk5TAAtAc6ZeVyCYAAAAAWJLR0QF+G/pxwAAADJJREFUCNdjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBnIA3DtcAPhVsAthTkDAFOfBKW9C1iqAAAAAElFTkSuQmCC");
}
.tree-details .toggle-icon {
width: 16px;
height: 16px;
/* vertically center the button */
position: absolute;
top: 50%;
margin-top: -9px;
margin-left: 6px;
}
.form-type {
color: #999;
}
.badge-error {
float: right;
background: #B0413E;
color: #FFF;
padding: 1px 4px;
font-size: 10px;
font-weight: bold;
vertical-align: middle;
}
.errors h3 {
color: #B0413E;
}
.errors th {
background: #B0413E;
color: #FFF;
}
.errors .toggle-icon {
background-color: #B0413E;
}
h3 a, h3 a:hover, h3 a:focus {
color: inherit;
text-decoration: inherit;
}
</style>
{% endblock %}
{% block panel %}
<h2>Forms</h2>
{% if collector.data.forms|length %}
<div class="window">
<div class="tree">
<h2>Forms</h2>
<ul>
{% for formName, formData in collector.data.forms %}
{{ form_tree_entry(formName, formData, true) }}
{% endfor %}
</ul>
</div>
<div id="tree-menu" class="tree">
<ul>
{% for formName, formData in collector.data.forms %}
{{ form_tree_entry(formName, formData, true) }}
{% endfor %}
</ul>
</div>
<div id="tree-details-container">
{% for formName, formData in collector.data.forms %}
{{ form_tree_details(formName, formData, collector.data.forms_by_hash) }}
{% endfor %}
</div>
{% else %}
<p><em>No forms were submitted for this request.</em></p>
<div class="empty">
<p>No forms were submitted for this request.</p>
</div>
{% endif %}
<script>
@ -444,14 +436,16 @@
{% else %}
<div class="toggle-icon empty"></div>
{% endif %}
{{ name|default('(no name)') }} {% if data.type_class is defined and data.type is defined %}[<abbr title="{{ data.type_class }}">{{ data.type }}</abbr>]{% endif %}
{% if data.errors is defined and data.errors|length > 0 %}
<div class="badge-error">{{ data.errors|length }}</div>
<div class="badge-error">{{ data.errors|length }}</div>
{% endif %}
</div>
{% if data.children is not empty %}
<ul id="{{ data.id }}-children"{% if not expanded %} class="hidden"{% endif %}>
<ul id="{{ data.id }}-children" {% if not expanded %}class="hidden"{% endif %}>
{% for childName, childData in data.children %}
{{ tree.form_tree_entry(childName, childData, false) }}
{% endfor %}
@ -462,7 +456,7 @@
{% macro form_tree_details(name, data, forms_by_hash) %}
{% import _self as tree %}
<div class="tree-details" {% if data.id is defined %} id="{{ data.id }}-details"{% endif %}>
<div class="tree-details" {% if data.id is defined %}id="{{ data.id }}-details"{% endif %}>
<h2>
{{ name|default('(no name)') }}
{% if data.type_class is defined and data.type is defined %}
@ -474,17 +468,19 @@
<div class="errors">
<h3>
<a class="toggle-button" data-toggle-target-id="{{ data.id }}-errors" href="#">
Errors
<span class="toggle-icon"></span>
Errors <span class="toggle-icon"></span>
</a>
</h3>
<table id="{{ data.id }}-errors">
<tr>
<th>Message</th>
<th>Origin</th>
<th>Cause</th>
</tr>
<thead>
<tr>
<th>Message</th>
<th>Origin</th>
<th>Cause</th>
</tr>
</thead>
<tbody>
{% for error in data.errors %}
<tr>
<td>{{ error.message }}</td>
@ -500,10 +496,11 @@
<td>
{% for trace in error.trace %}
{% if not loop.first %}
<br/>Caused by:<br/><br/>
<span class="newline">Caused by:</span>
{% endif %}
{% if trace.root is defined %}
<strong>{{ trace.class }}</strong><br/>
<strong class="newline">{{ trace.class }}</strong>
<pre>
{{- trace.root -}}
{%- if trace.path is not empty -%}
@ -512,7 +509,7 @@
{%- endif %} = {{ trace.value -}}
</pre>
{% elseif trace.message is defined %}
<strong>{{ trace.class }}</strong><br/>
<strong class="newline">{{ trace.class }}</strong>
<pre>{{ trace.message }}</pre>
{% else %}
<pre>{{ trace }}</pre>
@ -523,6 +520,7 @@
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
@ -530,37 +528,44 @@
{% if data.default_data is defined %}
<h3>
<a class="toggle-button" data-toggle-target-id="{{ data.id }}-default_data" href="#">
Default Data
<span class="toggle-icon"></span>
Default Data <span class="toggle-icon"></span>
</a>
</h3>
<div id="{{ data.id }}-default_data">
<table>
<tr>
<th width="180">Model Format</th>
<td>
{% if data.default_data.model is defined %}
<pre>{{ data.default_data.model }}</pre>
{% else %}
<em>same as normalized format</em>
{% endif %}
</td>
</tr>
<tr>
<th>Normalized Format</th>
<td><pre>{{ data.default_data.norm }}</pre></td>
</tr>
<tr>
<th>View Format</th>
<td>
{% if data.default_data.view is defined %}
<pre>{{ data.default_data.view }}</pre>
{% else %}
<em>same as normalized format</em>
{% endif %}
</td>
</tr>
<thead>
<tr>
<th width="180">Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<th class="font-normal" scope="row">Model Format</th>
<td>
{% if data.default_data.model is defined %}
{{ data.default_data.model }}
{% else %}
<em class="font-normal text-muted">same as normalized format</em>
{% endif %}
</td>
</tr>
<tr>
<th class="font-normal" scope="row">Normalized Format</th>
<td>{{ data.default_data.norm }}</td>
</tr>
<tr>
<th class="font-normal" scope="row">View Format</th>
<td>
{% if data.default_data.view is defined %}
{{ data.default_data.view }}
{% else %}
<em class="font-normal text-muted">same as normalized format</em>
{% endif %}
</td>
</tr>
</tbody>
</table>
</div>
{% endif %}
@ -568,41 +573,50 @@
{% if data.submitted_data is defined %}
<h3>
<a class="toggle-button" data-toggle-target-id="{{ data.id }}-submitted_data" href="#">
Submitted Data
<span class="toggle-icon"></span>
Submitted Data <span class="toggle-icon"></span>
</a>
</h3>
<div id="{{ data.id }}-submitted_data">
{% if data.submitted_data.norm is defined %}
<table>
<tr>
<th width="180">View Format</th>
<td>
{% if data.submitted_data.view is defined %}
<pre>{{ data.submitted_data.view }}</pre>
{% else %}
<em>same as normalized format</em>
{% endif %}
</td>
</tr>
<tr>
<th>Normalized Format</th>
<td><pre>{{ data.submitted_data.norm }}</pre></td>
</tr>
<tr>
<th>Model Format</th>
<td>
{% if data.submitted_data.model is defined %}
<pre>{{ data.submitted_data.model }}</pre>
{% else %}
<em>same as normalized format</em>
{% endif %}
</td>
</tr>
<thead>
<tr>
<th width="180">Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<th class="font-normal" scope="row">View Format</th>
<td>
{% if data.submitted_data.view is defined %}
{{ data.submitted_data.view }}
{% else %}
<em class="font-normal text-muted">same as normalized format</em>
{% endif %}
</td>
</tr>
<tr>
<th class="font-normal" scope="row">Normalized Format</th>
<td>{{ data.submitted_data.norm }}</td>
</tr>
<tr>
<th class="font-normal" scope="row">Model Format</th>
<td>
{% if data.submitted_data.model is defined %}
{{ data.submitted_data.model }}
{% else %}
<em class="font-normal text-muted">same as normalized format</em>
{% endif %}
</td>
</tr>
</tbody>
</table>
{% else %}
<p><em>This form was not submitted.</em></p>
<div class="empty">
<p>This form was not submitted.</p>
</div>
{% endif %}
</div>
{% endif %}
@ -610,35 +624,40 @@
{% if data.passed_options is defined %}
<h3>
<a class="toggle-button" data-toggle-target-id="{{ data.id }}-passed_options" href="#">
Passed Options
<span class="toggle-icon"></span>
Passed Options <span class="toggle-icon"></span>
</a>
</h3>
<div id="{{ data.id }}-passed_options">
{% if data.passed_options|length %}
<table>
<tr>
<th width="180">Option</th>
<th>Passed Value</th>
<th>Resolved Value</th>
</tr>
<thead>
<tr>
<th width="180">Option</th>
<th>Passed Value</th>
<th>Resolved Value</th>
</tr>
</thead>
<tbody>
{% for option, value in data.passed_options %}
<tr>
<th>{{ option }}</th>
<td><pre>{{ value }}</pre></td>
<td>{{ value }}</td>
<td>
{% if data.resolved_options[option] is same as(value) %}
<em>same as passed value</em>
{% if data.resolved_options[option] is sameas(value) %}
<em class="font-normal text-muted">same as passed value</em>
{% else %}
<pre>{{ data.resolved_options[option] }}</pre>
{{ data.resolved_options[option] }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p><em>No options where passed when constructing this form.</em></p>
<div class="empty">
<p>No options where passed when constructing this form.</p>
</div>
{% endif %}
</div>
{% endif %}
@ -646,23 +665,26 @@
{% if data.resolved_options is defined %}
<h3>
<a class="toggle-button" data-toggle-target-id="{{ data.id }}-resolved_options" href="#">
Resolved Options
<span class="toggle-icon"></span>
Resolved Options <span class="toggle-icon"></span>
</a>
</h3>
<div id="{{ data.id }}-resolved_options" class="hidden">
<table>
<tr>
<th width="180">Option</th>
<th>Value</th>
</tr>
<thead>
<tr>
<th width="180">Option</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{% for option, value in data.resolved_options %}
<tr>
<th>{{ option }}</th>
<td><pre>{{ value }}</pre></td>
<th scope="row">{{ option }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
@ -670,23 +692,26 @@
{% if data.view_vars is defined %}
<h3>
<a class="toggle-button" data-toggle-target-id="{{ data.id }}-view_vars" href="#">
View Variables
<span class="toggle-icon"></span>
View Variables <span class="toggle-icon"></span>
</a>
</h3>
<div id="{{ data.id }}-view_vars" class="hidden">
<table>
<tr>
<th width="180">Variable</th>
<th>Value</th>
</tr>
<thead>
<tr>
<th width="180">Variable</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{% for variable, value in data.view_vars %}
<tr>
<th>{{ variable }}</th>
<td><pre>{{ value }}</pre></td>
<th scope="row">{{ variable }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}

View File

@ -1,6 +1,6 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% import _self as logger %}
{% import _self as helper %}
{% block toolbar %}
{% if collector.counterrors or collector.countdeprecations or collector.countscreams %}
@ -33,107 +33,141 @@
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="26" height="32" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 26 32" enable-background="new 0 0 26 32" xml:space="preserve"><path fill="#3F3F3F" d="M23.6 3.4h-1.7V1.7c0-0.9-0.8-1.7-1.7-1.7H1.7C0.8 0 0 0.8 0 1.7v3.4v21.9C0 29.7 2.3 32 5.1 32h18.5 c0.9 0 1.7-0.8 1.7-1.7V5.1C25.3 4.1 24.5 3.4 23.6 3.4z M8.4 18.5h5.1v5.1H8.4V18.5z M8.4 15.2V5.1h5.1v10.1H8.4z M23.6 28.6 c0 0.9-0.8 1.7-1.7 1.7H6.7c-1.5 0-2.8-0.7-3.7-1.7h17.2c0.9 0 1.7-0.8 1.7-1.7V5.1c0.9 0 1.7 0.8 1.7 1.7V28.6z"/></svg></span>
<strong>Logs</strong>
{% if collector.counterrors or collector.countdeprecations or collector.countscreams %}
{% set error_count = collector.counterrors + collector.countdeprecations + collector.countscreams %}
<span class="count">
<span>{{ error_count }}</span>
</span>
{% endif %}
</span>
<span class="label label-status-{{ collector.counterrors ? 'error' : collector.countdeprecations ? 'warning' }} {{ collector.logs is empty ? 'disabled' }}">
<span class="icon">{{ include('@WebProfiler/Icon/logger.svg') }}</span>
<strong>Logs</strong>
{% if collector.counterrors or collector.countdeprecations %}
<span class="count">
<span>{{ collector.counterrors ?: collector.countdeprecations }}</span>
</span>
{% endif %}
</span>
{% endblock %}
{% block panel %}
<h2>Logs</h2>
<h2>Log Messages</h2>
{% set priority = request.query.get('priority', 0) %}
<table>
<tr>
<th>Filter</th>
<td>
<form id="priority-form" action="" method="get" style="display: inline">
<input type="hidden" name="panel" value="logger">
<label for="priority">Min. Priority</label>
<select id="priority" name="priority" onchange="document.getElementById('priority-form').submit(); ">
{# values < 0 are custom levels #}
{% for value, level in collector.priorities %}
{% if not priority and value > 100 %}
{% set priority = value %}
{% endif %}
<option value="{{ value }}"{{ value == priority ? ' selected' : '' }}>{{ level.name }} ({{ level.count }})</option>
{% endfor %}
{% if collector.countdeprecations %}
{% if not priority %}
{% set priority = "-100" %}
{% endif %}
<option value="-100"{{ "-100" == priority ? ' selected' : '' }}>DEPRECATION only ({{ collector.countdeprecations }})</option>
{% endif %}
</select>
<noscript>
<input type="submit" value="refresh">
</noscript>
</form>
</td>
</tr>
</table>
{% if collector.logs %}
<table>
<tr>
<th>#</th>
<th>Priority</th>
<th>Channel</th>
<th>Message and context</th>
</tr>
{% set log_loop_index = 0 %}
{% for log in collector.logs %}
{% set is_deprecation = log.context.level is defined and log.context.type is defined and (constant('E_DEPRECATED') == log.context.type or constant('E_USER_DEPRECATED') == log.context.type) %}
{% if priority == '-100' ? is_deprecation : log.priority >= priority %}
{% set log_loop_index = log_loop_index + 1 %}
<tr class="{{ cycle(['odd', 'even'], log_loop_index) }}{% if log.context.scream is defined %} scream{% elseif log.priority >= 400 %} error{% elseif log.priority >= 300 or is_deprecation %} warning{% endif %}">
<td>{{ log_loop_index }}</td>
<td>{{ is_deprecation ? 'DEPRECATION' : log.priorityName }}</td>
<td>{{ log.channel is defined ? log.channel }}</td>
<td>{{ logger.display_message(loop.index, log, is_deprecation) }}</td>
</tr>
{% endif %}
{% else %}
<tr><td colspan="4"><em>No logs available for {{ priority }} priority.</em></td></tr>
{% endfor %}
</table>
{% if collector.logs is empty %}
<div class="empty">
<p>No log messages available.</p>
</div>
{% else %}
<p>
<em>No logs available.</em>
</p>
{# sort collected logs in groups #}
{% set deprecation_logs, debug_logs, info_and_error_logs = [], [], [] %}
{% for log in collector.logs %}
{% if log.context.level is defined and log.context.type is defined and log.context.type in [constant('E_DEPRECATED'), constant('E_USER_DEPRECATED')] %}
{% set deprecation_logs = deprecation_logs|merge([log]) %}
{% elseif log.priorityName == 'DEBUG' %}
{% set debug_logs = debug_logs|merge([log]) %}
{% else %}
{% set info_and_error_logs = info_and_error_logs|merge([log]) %}
{% endif %}
{% endfor %}
<div class="sf-tabs">
<div class="tab">
<h3 class="tab-title">Info. &amp; Errors <span class="badge">{{ info_and_error_logs|length }}</span></h3>
<div class="tab-content">
{% if info_and_error_logs is empty %}
<div class="empty">
<p>There are no log messages of this level.</p>
</div>
{% else %}
{{ helper.render_table(info_and_error_logs, true) }}
{% endif %}
</div>
</div>
<div class="tab">
{# 'deprecation_logs|length' is not used because deprecations are
now grouped and the group count doesn't match the message count #}
<h3 class="tab-title">Deprecations <span class="badge">{{ collector.countdeprecations|default(0) }}</span></h3>
<div class="tab-content">
{% if deprecation_logs is empty %}
<div class="empty">
<p>There are no log messages about deprecated features.</p>
</div>
{% else %}
{{ helper.render_table(deprecation_logs, false, true) }}
{% endif %}
</div>
</div>
<div class="tab">
<h3 class="tab-title">Debug <span class="badge">{{ debug_logs|length }}</span></h3>
<div class="tab-content">
{% if debug_logs is empty %}
<div class="empty">
<p>There are no log messages of this level.</p>
</div>
{% else %}
{{ helper.render_table(debug_logs) }}
{% endif %}
</div>
</div>
</div>
{% endif %}
{% endblock %}
{% macro render_table(logs, show_level = false, is_deprecation = false) %}
{% import _self as helper %}
{% set channel_is_defined = (logs|first).channel is defined %}
{% macro display_message(log_index, log, is_deprecation) %}
{{ is_deprecation ? 'DEPRECATED' : log.priorityName }} - {{ log.message }}
<table class="logs">
<thead>
<tr>
<th>{{ show_level ? 'Level' : 'Time' }}</th>
{% if channel_is_defined %}<th>Channel</th>{% endif %}
<th>Message</th>
</tr>
</thead>
<tbody>
{% for log in logs %}
{% set css_class = is_deprecation ? ''
: log.priorityName in ['CRITICAL', 'ERROR', 'ALERT', 'EMERGENCY'] ? 'status-error'
: log.priorityName in ['NOTICE', 'WARNING'] ? 'status-warning'
%}
<tr class="{{ css_class }}">
<td class="font-normal text-small">
{% if show_level %}
<span class="colored text-bold nowrap">{{ log.priorityName }}</span>
{% endif %}
<span class="text-muted nowrap newline">{{ log.timestamp|date('H:i:s') }}</span>
</td>
{% if channel_is_defined %}
<td class="font-normal text-small text-bold nowrap">{{ log.channel }}</td>
{% endif %}
<td class="font-normal">{{ helper.render_log_message(loop.index, log, is_deprecation) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endmacro %}
{% macro render_log_message(log_index, log, is_deprecation = false) %}
{{ log.message }}
{% if is_deprecation %}
{% set stack = log.context.stack|default([]) %}
{% set id = 'sf-call-stack-' ~ log_index %}
{% if log.context.errorCount is defined %}
({{ log.context.errorCount }}x)
<span class="text-small text-bold">({{ log.context.errorCount }} times)</span>
{% endif %}
{% if stack %}
<a href="#" onclick="Sfjs.toggle('{{ id }}', document.getElementById('{{ id }}-on'), document.getElementById('{{ id }}-off')); return false;">
<img class="toggle" id="{{ id }}-off" alt="-" src="data:image/gif;base64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1+mC24IvK6ePx+Wa44dXs92+942e54o3L6W2844/M6dnu+P/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD/ER/wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO+hE0EoNAstEYGxG9heIhCADs=" style="display:none">
<img class="toggle" id="{{ id }}-on" alt="+" src="data:image/gif;base64,R0lGODlhEgASAMQTANft99/v+Ga44bHb8ITG52S44dXs9+z1+uPx+YvK6WC24G+944/M6W28443L6dnu+Ge54v/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5/vFID/DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7" style="display:inline">
</a>
<a class="text-small sf-toggle" data-toggle-selector="#{{ id }}" data-toggle-alt-content="Hide stack trace">Show strack trace</a>
{% endif %}
{% for index, call in stack if index > 1 %}
{% if index == 2 %}
<ul class="sf-call-stack" id="{{ id }}" style="display: none">
<ul class="sf-call-stack" id="{{ id }}" class="hidden">
{% endif %}
{% if call.class is defined %}
{% set from = call.class|abbr_class ~ '::' ~ call.function|abbr_method() %}
@ -145,7 +179,7 @@
{% set from = '-' %}
{% endif %}
<li>Called from {{ call.file is defined and call.line is defined ? call.file|format_file(call.line, from) : from|raw }}</li>
<li><span class="text-small">Called from</span> {{ call.file is defined and call.line is defined ? call.file|format_file(call.line, from) : from|raw }}</li>
{% if index == stack|length - 1 %}
</ul>
@ -153,10 +187,11 @@
{% endfor %}
{% else %}
{% if log.context is defined and log.context is not empty %}
<br />
<small>
<strong>Context</strong>: {{ log.context|json_encode(64 b-or 256) }}
</small>
<span class="metadata">
<strong>Context</strong>: {{ log.context|json_encode(64 b-or 256)|replace({
'{"' : '{ "', '"}' : '" }', '":{' : '": {', '":"' : '": "', '","' : '", "'
}) }}
</span>
{% endif %}
{% endif %}
{% endmacro %}

View File

@ -16,9 +16,9 @@
<div class="sf-toolbar-info-piece">
<b>PHP memory limit</b>
<span>{{ collector.memoryLimit == -1 ? '&infin;' : '%.0f'|format(collector.memoryLimit / 1024 / 1024)|escape }} MB</span>
<span>{{ collector.memoryLimit == -1 ? 'Unlimited' : '%.0f MB'|format(collector.memoryLimit / 1024 / 1024) }}</span>
</div>
{% endset %}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false, status: status_color }) }}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url, name: 'time', status: status_color }) }}
{% endblock %}

View File

@ -1,8 +1,6 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% block toolbar %}
{% set request_handler %}
{% if collector.controller.class is defined %}
{% set link = collector.controller.file|file_link(collector.controller.line) %}
@ -20,7 +18,7 @@
{% endif %}
{% endset %}
{% set request_status_code_color = (400 > collector.statuscode) ? ((200 == collector.statuscode) ? 'green' : 'yellow') : 'red' %}
{% set request_status_code_color = (collector.statuscode >= 400) ? 'red' : (collector.statuscode >= 300) ? 'yellow' : 'green' %}
{% set icon %}
<span class="sf-toolbar-status sf-toolbar-status-{{ request_status_code_color }}">{{ collector.statuscode }}</span>
@ -31,148 +29,198 @@
{% endset %}
{% set text %}
{% spaceless %}
<div class="sf-toolbar-info-piece">
<b>HTTP status</b>
<span>{{ collector.statuscode }} {{ collector.statustext }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Controller</b>
<span>{{ request_handler }}</span>
</div>
{% if collector.controller.class is defined %}
<div class="sf-toolbar-info-piece">
<b>HTTP status</b>
<span>{{ collector.statuscode }} {{ collector.statustext }}</span>
<b>Controller class</b>
<span>{{ collector.controller.class }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Controller</b>
<span>{{ request_handler }}</span>
</div>
{% if collector.controller.class is defined %}
<div class="sf-toolbar-info-piece">
<b>Controller class</b>
<span>{{ collector.controller.class }}</span>
</div>
{% endif %}
<div class="sf-toolbar-info-piece">
<b>Route name</b>
<span>{{ collector.route|default('NONE') }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Has session</b>
<span>{% if collector.sessionmetadata|length %}yes{% else %}no{% endif %}</span>
</div>
{% endspaceless %}
{% endif %}
<div class="sf-toolbar-info-piece">
<b>Route name</b>
<span>{{ collector.route|default('NONE') }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Has session</b>
<span>{% if collector.sessionmetadata|length %}yes{% else %}no{% endif %}</span>
</div>
{% endset %}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url }) }}
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="38" height="28" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 38 28" enable-background="new 0 0 38 28" xml:space="preserve"><path fill="#3F3F3F" d="M26.7 20.5c0 0.3 0 0.7 0.1 1c-1.1 1-1.6 1.6-1.8 1.8c0 0 0 0.1 0 0.1c1 1.3 1.5 2 1.5 2 c0.1 0 0.4-0.1 1.1-0.4c0.6-0.3 1-0.6 1.3-0.7c0.2 0.1 0.4 0.2 0.5 0.2c0.1 0 0.3 0.1 0.5 0.2c0.1 0.3 0.2 0.8 0.4 1.4 s0.3 1 0.4 1.1c0 0 0.8-0.1 2.5-0.3c0.1 0 0.1 0 0.1-0.1c0.1-0.3 0.2-1.1 0.1-2.5c0.3-0.2 0.6-0.4 0.8-0.6c1.6 0.5 2.5 0.7 2.6 0.5 l1-2.2l0 0c0.1-0.2-0.6-0.7-2.2-1.5c0-0.4 0-0.7-0.1-1c1.1-1 1.6-1.6 1.8-1.8c0 0 0-0.1 0-0.1c-1-1.3-1.4-1.9-1.5-2l-0.1 0 c-0.6 0.2-1.4 0.6-2.2 1.2c-0.2-0.1-0.4-0.2-0.5-0.2c-0.1 0-0.3-0.1-0.5-0.2c-0.1-0.3-0.2-0.8-0.4-1.4c-0.2-0.7-0.3-1-0.4-1.1 c0 0-0.2 0-0.6 0c-0.4 0-0.8 0.1-1.2 0.1C29.4 14 29.2 14 29.2 14c-0.1 0-0.1 0-0.1 0.1c-0.1 0.3-0.2 1.1-0.1 2.5 c-0.3 0.2-0.6 0.4-0.8 0.6c-1.6-0.5-2.5-0.7-2.6-0.5l-1 2.2C24.5 19.1 25.2 19.6 26.7 20.5z M30.3 18.4c0.6-0.2 1.1-0.2 1.7 0 c0.6 0.2 0.9 0.6 1.2 1.2c0.2 0.6 0.2 1.1 0 1.7c-0.2 0.6-0.6 1-1.2 1.2c-0.6 0.2-1.1 0.2-1.7 0c-0.6-0.2-1-0.6-1.2-1.2 c-0.2-0.6-0.2-1.1 0-1.7C29.3 19.1 29.7 18.7 30.3 18.4z"/><path fill="#3F3F3F" d="M25.9 11.1c0-0.1 0-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.2L22.3 10c-0.1-0.5-0.4-1-0.7-1.7 c0.2-0.3 0.5-0.7 0.9-1.2c0.4-0.5 0.7-0.9 0.8-1.1c0.1-0.1 0.1-0.3 0.1-0.4c0-0.4-1-1.4-2.9-3.2c-0.1-0.1-0.3-0.2-0.4-0.2 c-0.2 0-0.3 0-0.4 0.1l-2.4 1.8c-0.6-0.3-1.1-0.5-1.5-0.6l-0.5-3.1c0-0.1-0.1-0.3-0.2-0.4C15.1 0.1 15 0 14.8 0h-3.8 c-0.3 0-0.5 0.2-0.6 0.5c-0.2 0.6-0.3 1.7-0.5 3.1C9.4 3.8 8.9 4 8.4 4.2L6.1 2.4C6 2.3 5.8 2.3 5.7 2.3c-0.3 0-0.8 0.4-1.6 1.2 C3.3 4.3 2.7 4.9 2.4 5.3C2.3 5.4 2.3 5.5 2.3 5.7c0 0.1 0 0.3 0.1 0.4C3.2 7 3.8 7.8 4.2 8.4C4 9 3.7 9.5 3.6 10l-3.1 0.5 c-0.1 0-0.2 0.1-0.3 0.2C0 10.8 0 10.9 0 11.1v3.7c0 0.1 0 0.3 0.1 0.4c0.1 0.1 0.2 0.2 0.3 0.2l3.1 0.5c0.2 0.5 0.4 1.1 0.7 1.7 c-0.2 0.3-0.5 0.7-1 1.2c-0.4 0.5-0.7 0.9-0.8 1.1c-0.1 0.1-0.1 0.3-0.1 0.4c0 0.4 1 1.4 2.9 3.2c0.1 0.1 0.3 0.2 0.4 0.2 c0.2 0 0.3 0 0.4-0.1l2.4-1.8C9 22 9.5 22.2 10 22.3l0.5 3.1c0 0.1 0.1 0.3 0.2 0.4c0.1 0.1 0.3 0.2 0.4 0.2h3.8 c0.3 0 0.5-0.2 0.6-0.5c0.2-0.6 0.3-1.7 0.5-3.1c0.5-0.2 1.1-0.4 1.6-0.6l2.3 1.8c0.1 0.1 0.3 0.1 0.4 0.1c0.3 0 0.8-0.4 1.6-1.2 c0.8-0.8 1.4-1.4 1.7-1.8c0.1-0.1 0.1-0.2 0.1-0.4c0-0.1 0-0.3-0.1-0.4c-0.8-0.9-1.4-1.7-1.8-2.3c0.3-0.6 0.5-1.1 0.6-1.5l3.1-0.5 c0.1 0 0.2-0.1 0.3-0.2c0.1-0.1 0.1-0.3 0.1-0.4L25.9 11.1L25.9 11.1z M16.6 16.6c-1 1-2.2 1.5-3.7 1.5s-2.7-0.5-3.7-1.5 c-1-1-1.5-2.2-1.5-3.7s0.5-2.7 1.5-3.7c1-1 2.2-1.5 3.7-1.5s2.7 0.5 3.7 1.5c1 1 1.5 2.2 1.5 3.7S17.6 15.6 16.6 16.6z"/><circle fill="#3F3F3F" cx="12.9" cy="12.9" r="2.8"/></svg></span>
<strong>Request</strong>
</span>
<span class="label">
<span class="icon">{{ include('@WebProfiler/Icon/request.svg') }}</span>
<strong>Request / Response</strong>
</span>
{% endblock %}
{% block panel %}
<h2>Request GET Parameters</h2>
<div class="sf-tabs">
<div class="tab">
<h3 class="tab-title">Request</h3>
{% if collector.requestquery.all|length %}
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': collector.requestquery } only %}
{% else %}
<p>
<em>No GET parameters</em>
</p>
{% endif %}
<div class="tab-content">
<h3>GET Parameters</h3>
<h2>Request POST Parameters</h2>
{% if collector.requestquery.all is empty %}
<div class="empty">
<p>No GET parameters</p>
</div>
{% else %}
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: collector.requestquery }, with_context = false) }}
{% endif %}
{% if collector.requestrequest.all|length %}
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': collector.requestrequest } only %}
{% else %}
<p>
<em>No POST parameters</em>
</p>
{% endif %}
<h3>POST Parameters</h3>
<h2>Request Attributes</h2>
{% if collector.requestrequest.all is empty %}
<div class="empty">
<p>No POST parameters</p>
</div>
{% else %}
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: collector.requestrequest }, with_context = false) }}
{% endif %}
{% if collector.requestattributes.all|length %}
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': collector.requestattributes } only %}
{% else %}
<p>
<em>No attributes</em>
</p>
{% endif %}
<h3>Request Attributes</h3>
<h2>Request Cookies</h2>
{% if collector.requestattributes.all is empty %}
<div class="empty">
<p>No attributes</p>
</div>
{% else %}
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: collector.requestattributes }, with_context = false) }}
{% endif %}
{% if collector.requestcookies.all|length %}
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': collector.requestcookies } only %}
{% else %}
<p>
<em>No cookies</em>
</p>
{% endif %}
<h3>Cookies</h3>
<h2>Request Headers</h2>
{% if collector.requestcookies.all is empty %}
<div class="empty">
<p>No cookies</p>
</div>
{% else %}
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: collector.requestcookies }, with_context = false) }}
{% endif %}
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': collector.requestheaders } only %}
<h3>Request Headers</h3>
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: collector.requestheaders, labels: ['Header', 'Value'] }, with_context = false) }}
<h2>Request Content</h2>
<h3>Request Content</h3>
{% if collector.content == false %}
<p><em>Request content not available (it was retrieved as a resource).</em></p>
{% elseif collector.content %}
<pre>{{ collector.content }}</pre>
{% else %}
<p><em>No content</em></p>
{% endif %}
{% if collector.content == false %}
<div class="empty">
<p>Request content not available (it was retrieved as a resource).</p>
</div>
{% elseif collector.content %}
<div class="card">
<pre class="break-long-words">{{ collector.content }}</pre>
</div>
{% else %}
<div class="empty">
<p>No content</p>
</div>
{% endif %}
<h2>Request Server Parameters</h2>
<h3>Server Parameters</h3>
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: collector.requestserver }, with_context = false) }}
</div>
</div>
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': collector.requestserver } only %}
<div class="tab">
<h3 class="tab-title">Response</h3>
<h2>Response Headers</h2>
<div class="tab-content">
<h3>Response Headers</h3>
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': collector.responseheaders } only %}
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: collector.responseheaders, labels: ['Header', 'Value'] }, with_context = false) }}
</div>
</div>
<h2>Session Metadata</h2>
<div class="tab {{ collector.sessionmetadata is empty ? 'disabled' }}">
<h3 class="tab-title">Session</h3>
{% if collector.sessionmetadata|length %}
{% include '@WebProfiler/Profiler/table.html.twig' with { 'data': collector.sessionmetadata } only %}
{% else %}
<p>
<em>No session metadata</em>
</p>
{% endif %}
<div class="tab-content">
<h3>Session Metadata</h3>
<h2>Session Attributes</h2>
{% if collector.sessionmetadata is empty %}
<div class="empty">
<p>No session metadata</p>
</div>
{% else %}
{{ include('@WebProfiler/Profiler/table.html.twig', { data: collector.sessionmetadata }, with_context = false) }}
{% endif %}
{% if collector.sessionattributes|length %}
{% include '@WebProfiler/Profiler/table.html.twig' with { 'data': collector.sessionattributes } only %}
{% else %}
<p>
<em>No session attributes</em>
</p>
{% endif %}
<h3>Session Attributes</h3>
<h2>Flashes</h2>
{% if collector.sessionattributes is empty %}
<div class="empty">
<p>No session attributes</p>
</div>
{% else %}
{{ include('@WebProfiler/Profiler/table.html.twig', { data: collector.sessionattributes, labels: ['Attribute', 'Value'] }, with_context = false) }}
{% endif %}
</div>
</div>
{% if collector.flashes|length %}
{% include '@WebProfiler/Profiler/table.html.twig' with { 'data': collector.flashes } only %}
{% else %}
<p>
<em>No flashes</em>
</p>
{% endif %}
<div class="tab {{ collector.flashes is empty ? 'disabled' }}">
<h3 class="tab-title">Flashes</h3>
{% if profile.parent %}
<h2><a href="{{ path('_profiler', { 'token': profile.parent.token }) }}">Parent request: {{ profile.parent.token }}</a></h2>
<div class="tab-content">
<h3>Flashes</h3>
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': profile.parent.getcollector('request').requestattributes } only %}
{% endif %}
{% if collector.flashes is empty %}
<div class="empty">
<p>No flash messages were created.</p>
</div>
{% else %}
{{ include('@WebProfiler/Profiler/table.html.twig', { data: collector.flashes }, with_context = false) }}
{% endif %}
</div>
</div>
{% if profile.children|length %}
<h2>Sub requests</h2>
{% if profile.parent %}
<div class="tab">
<h3 class="tab-title">Parent Request</h3>
{% for child in profile.children %}
<h3><a href="{{ path('_profiler', { 'token': child.token }) }}">{{ child.token }}</a></h3>
{% include '@WebProfiler/Profiler/bag.html.twig' with { 'bag': child.getcollector('request').requestattributes } only %}
{% endfor %}
{% endif %}
<div class="tab-content">
<h3>
<a href="{{ path('_profiler', { token: profile.parent.token }) }}">Return to parent request</a>
<small>(token = {{ profile.parent.token }})</small>
</h3>
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: profile.parent.getcollector('request').requestattributes }, with_context = false) }}
</div>
</div>
{% endif %}
{% if profile.children|length %}
<div class="tab">
<h3 class="tab-title">Sub Requests <span class="badge">{{ profile.children|length }}</span></h3>
<div class="tab-content">
{% for child in profile.children %}
<h3>
<a href="{{ path('_profiler', { token: child.token }) }}">
{{- child.getcollector('request').requestattributes.get('_controller') -}}
</a>
<small>(token = {{ child.token }})</small>
</h3>
{{ include('@WebProfiler/Profiler/bag.html.twig', { bag: child.getcollector('request').requestattributes }, with_context = false) }}
{% endfor %}
</div>
</div>
{% endif %}
</div>
{% endblock %}

View File

@ -1,15 +1,14 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% block toolbar %}
{% endblock %}
{% block toolbar %}{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="32" height="32" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve"><g><path fill="#3F3F3F" d="M15 2c-1.1 0-2 0.9-2 2v25c0 1.1 0.9 2 2 2s2-0.9 2-2V4C17 2.9 16.1 2 15 2z"/><path fill="#3F3F3F" d="M30.7 8.2l-2.9-2.9C27.6 5.1 27.3 5 27 5h0h0h-9v8h9c0.3 0 0.6-0.1 0.8-0.3l2.9-2.9 C31.1 9.4 31.1 8.6 30.7 8.2z"/><path fill="#3F3F3F" d="M5 8L5 8C4.7 8 4.4 8.1 4.2 8.3l-2.9 2.9c-0.4 0.4-0.4 1.1 0 1.6l2.9 2.9C4.4 15.9 4.7 16 5 16h7V8H5L5 8z"/><path fill="#3F3F3F" d="M24.8 16.2c-0.2-0.2-0.3-0.2-0.5-0.2h0h0H18v6h6.2c0.2 0 0.4-0.1 0.5-0.2l2-2.2c0.3-0.3 0.3-0.9 0-1.2 L24.8 16.2z"/></g></svg></span>
<span class="icon">{{ include('@WebProfiler/Icon/router.svg') }}</span>
<strong>Routing</strong>
</span>
{% endblock %}
{% block panel %}
{{ render(path('_profiler_router', {'token': token})) }}
{{ render(path('_profiler_router', { token: token })) }}
{% endblock %}

View File

@ -1,17 +1,16 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% from _self import display_timeline, dump_request_data %}
{% import _self as helper %}
{% if colors is not defined %}
{% set colors = {
'default': '#aacd4e',
'section': '#666',
'event_listener': '#3dd',
'event_listener_loading': '#add',
'template': '#dd3',
'doctrine': '#d3d',
'propel': '#f4d',
'child_sections': '#eed',
'default': '#999',
'section': '#444',
'event_listener': '#00B8F5',
'event_listener_loading': '#00B8F5',
'template': '#66CC00',
'doctrine': '#FF6633',
'propel': '#FF6633',
} %}
{% endif %}
@ -41,63 +40,99 @@
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="30" height="33" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 30 33" enable-background="new 0 0 30 33" xml:space="preserve"><rect x="11" y="2" fill="#3F3F3F" width="8" height="3"/><path fill="#3F3F3F" d="M15 6.1c-6.6 0-12 5.4-12 12s5.4 12 12 12s12-5.4 12-12S21.6 6.1 15 6.1z M22 20h-6h-3V10h3v7h6V20z"/></svg></span>
<strong>Timeline</strong>
</span>
<span class="label">
<span class="icon">{{ include('@WebProfiler/Icon/time.svg') }}</span>
<strong>Performance</strong>
</span>
{% endblock %}
{% block panel %}
<h2>Timeline</h2>
{% if collector.events|length %}
{{ block('panelContent') }}
<h2>Performance metrics</h2>
<div class="metrics">
<div class="metric">
<span class="value">{{ '%.0f'|format(collector.duration) }} <span class="unit">ms</span></span>
<span class="label">Total execution time</span>
</div>
<div class="metric">
<span class="value">{{ '%.0f'|format(collector.inittime) }} <span class="unit">ms</span></span>
<span class="label">Symfony initialization</span>
</div>
{% if profile.children|length > 0 %}
<div class="metric">
<span class="value">{{ profile.children|length }}</span>
<span class="label">Sub-Requests</span>
</div>
{% set subrequests_time = 0 %}
{% for child in profile.children %}
{% set subrequests_time = subrequests_time + child.getcollector('time').events.__section__.duration %}
{% endfor %}
<div class="metric">
<span class="value">{{ subrequests_time }} <span class="unit">ms</span></span>
<span class="label">Sub-Requests time</span>
</div>
{% endif %}
{% if profile.collectors.memory %}
<div class="metric">
<span class="value">{{ '%.2f'|format(profile.collectors.memory.memory / 1024 / 1024) }} <span class="unit">MB</span></span>
<span class="label">Peak memory usage</span>
</div>
{% endif %}
</div>
<h2>Execution timeline</h2>
{% if collector.events is empty %}
<div class="empty">
<p>No timing events have been recorded. Are you sure that debugging is enabled in the kernel?</p>
</div>
{% else %}
<p>
<em>No timing events have been recorded. Are you sure that debugging is enabled in the kernel?</em>
</p>
{{ block('panelContent') }}
{% endif %}
{% endblock %}
{% block panelContent %}
<form id="timeline-control" action="" method="get">
<input type="hidden" name="panel" value="time">
<table>
<tr>
<th style="width: 20%">Total time</th>
<td>{{ '%.0f'|format(collector.duration) }} ms</td>
</tr>
<tr>
<th>Initialization time</th>
<td>{{ '%.0f'|format(collector.inittime) }} ms</td>
</tr>
<tr>
<th>Threshold</th>
<td><input type="number" size="3" name="threshold" value="1" min="0"> ms</td>
</tr>
</table>
<label for="threshold">Threshold</label>
<input type="number" size="3" name="threshold" id="threshold" value="3" min="0"> ms
<span class="help">(timeline only displays events with a duration longer than this threshold)</span>
</form>
<h3>
{{ profile.parent ? "Request" : "Main Request" }}
<small>
- {{ collector.events.__section__.duration }} ms
{% if profile.parent %}
- <a href="{{ path('_profiler', { 'token': profile.parent.token, 'panel': 'time' }) }}">parent</a>
{% endif %}
</small>
</h3>
{% if profile.parent %}
<h3>
Sub-Request {{ profile.getcollector('request').requestattributes.get('_controller') }}
<small>
{{ collector.events.__section__.duration }} ms
<a class="newline" href="{{ path('_profiler', { token: profile.parent.token, panel: 'time' }) }}">Return to parent request</a>
</small>
</h3>
{% elseif profile.children|length > 0 %}
<h3>
Main Request <small>{{ collector.events.__section__.duration }} ms</small>
</h3>
{% endif %}
{{ display_timeline('timeline_' ~ token, collector.events, colors) }}
{{ helper.display_timeline('timeline_' ~ token, collector.events, colors) }}
{% if profile.children|length %}
<p class="help">Note: sections with a striped background correspond to sub-requests.</p>
<h3>Sub-requests <small>({{ profile.children|length }})</small></h3>
{% for child in profile.children %}
{% set events = child.getcollector('time').events %}
<h3>
Sub-request "<a href="{{ path('_profiler', { 'token': child.token, 'panel': 'time' }) }}">{{ child.getcollector('request').requestattributes.get('_controller') }}</a>"
<small> - {{ events.__section__.duration }} ms</small>
</h3>
<h4>
<a href="{{ path('_profiler', { token: child.token, panel: 'time' }) }}">{{ child.getcollector('request').requestattributes.get('_controller') }}</a>
<small>{{ events.__section__.duration }} ms</small>
</h4>
{{ display_timeline('timeline_' ~ child.token, events, colors) }}
{{ helper.display_timeline('timeline_' ~ child.token, events, colors) }}
{% endfor %}
{% endif %}
@ -229,14 +264,19 @@
ctx.lineWidth = 0;
// For each event, draw a line.
ctx.strokeStyle = "#dfdfdf";
ctx.strokeStyle = "#CCC";
drawableEvents.forEach(function(event) {
event.periods.forEach(function(period) {
var timelineHeadPosition = x + period.start * ratio;
if (isChildEvent(event)) {
ctx.fillStyle = colors.child_sections;
/* create a striped background dynamically */
var img = new Image();
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKBAMAAAB/HNKOAAAAIVBMVEX////w8PDd7h7d7h7d7h7d7h7w8PDw8PDw8PDw8PDw8PAOi84XAAAAKUlEQVQImWNI71zAwMBQMYuBgY0BxExnADErGEDMTgYQE8hnAKtCZwIAlcMNSR9a1OEAAAAASUVORK5CYII=';
var pattern = ctx.createPattern(img, 'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(timelineHeadPosition, 0, (period.end - period.start) * ratio, canvasHeight);
} else if (isSectionEvent(event)) {
var timelineTailPosition = x + period.end * ratio;
@ -281,7 +321,7 @@
var timelineHeadPosition = x + period.start * ratio;
if (!isSectionEvent(event)) {
ctx.fillRect(timelineHeadPosition, h + 3, 2, 6);
ctx.fillRect(timelineHeadPosition, h + 3, 2, 8);
ctx.fillRect(timelineHeadPosition, h, (period.end - period.start) * ratio || 2, 6);
} else {
var timelineTailPosition = x + period.end * ratio;
@ -319,7 +359,7 @@
h += 30;
ctx.beginPath();
ctx.strokeStyle = "#dfdfdf";
ctx.strokeStyle = "#E0E0E0";
ctx.moveTo(0, h - 10);
ctx.lineTo(width, h - 10);
ctx.closePath();
@ -334,24 +374,28 @@
ctx.fillStyle = "#444";
ctx.font = "12px sans-serif";
text = event.name;
ms = " ~ " + (event.duration < 1 ? event.duration : parseInt(event.duration, 10)) + " ms / ~ " + event.memory + " MB";
ms = " " + (event.duration < 1 ? event.duration : parseInt(event.duration, 10)) + " ms / " + event.memory + " MB";
if (x + event.starttime * ratio + ctx.measureText(text + ms).width > width) {
ctx.textAlign = "end";
ctx.font = "10px sans-serif";
ctx.fillStyle = "#777";
xc = x + event.endtime * ratio - 1;
ctx.fillText(ms, xc, h);
xc -= ctx.measureText(ms).width;
ctx.font = "12px sans-serif";
ctx.fillStyle = "#222";
ctx.fillText(text, xc, h);
} else {
ctx.textAlign = "start";
ctx.font = "12px sans-serif";
ctx.font = "13px sans-serif";
ctx.fillStyle = "#222";
xc = x + event.starttime * ratio + 1;
ctx.fillText(text, xc, h);
xc += ctx.measureText(text).width;
ctx.font = "10px sans-serif";
ctx.font = "11px sans-serif";
ctx.fillStyle = "#777";
ctx.fillText(ms, xc, h);
}
@ -409,12 +453,12 @@
var requests_data = {
"max": {{ "%F"|format(collector.events.__section__.endtime) }},
"requests": [
{{ dump_request_data(token, profile, collector.events, collector.events.__section__.origin) }}
{{ helper.dump_request_data(token, profile, collector.events, collector.events.__section__.origin) }}
{% if profile.children|length %}
,
{% for child in profile.children %}
{{ dump_request_data(child.token, child, child.getcollector('time').events, collector.events.__section__.origin) }}{{ loop.last ? '' : ',' }}
{{ helper.dump_request_data(child.token, child, child.getcollector('time').events, collector.events.__section__.origin) }}{{ loop.last ? '' : ',' }}
{% endfor %}
{% endif %}
]

View File

@ -1,12 +1,12 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% import _self as translator %}
{% import _self as helper %}
{% block toolbar %}
{% if collector.messages|length %}
{% set icon %}
{{ include('@WebProfiler/Icon/translation.svg') }}
{% set status_color = collector.countMissings ? 'red' : collector.countFallbacks ? 'yellow' : '' %}
{% set status_color = collector.countMissings ? 'red' : collector.countFallbacks ? 'yellow' %}
{% set error_count = collector.countMissings + collector.countFallbacks %}
<span class="sf-toolbar-value">{{ error_count ?: collector.countdefines }}</span>
{% endset %}
@ -37,124 +37,161 @@
{% endblock %}
{% block menu %}
<span class="label">
<span class="icon"><svg width="35" height="28" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 417 300" enable-background="new 0 0 417 300" xml:space="preserve"><g id="Layer_1_1_"><g id="outline_1_"><path fill="#B5B5B6" d="M275.9,145c0,18.2-14.799,33-33,33H120.701l-36.3,42l-0.3-42H40c-18.2,0-33-14.8-33-33V44c0-18.2,14.8-33,33-33h202.9c18.199,0,33,14.8,33,33V145L275.9,145z"/></g><g enable-background="new"><path fill="#FFFFFF" d="M194.501,146.962h-23.898l-9.5-24.715h-43.492l-8.98,24.715H85.326l42.379-108.805h23.23L194.501,146.962zM154.052,103.915L139.06,63.54l-14.695,40.375H154.052z"/></g></g><g id="Layer_2_1_"><g id="japanese"><g id="outline"><path fill="#414141" d="M141.451,214c0,18.2,14.8,33,33,33h122.2l36.301,42l0.301-42h44.1c18.201,0,33-14.8,33-33V113c0-18.2-14.799-33-33-33H174.453c-18.201,0-33,14.8-33,33L141.451,214L141.451,214z"/></g><g enable-background="new"><path fill="#FFFFFF" d="M312.158,143.327c-0.455,1.672-0.912,3.344-1.215,5.016c22.039,6.08,31.766,21.431,31.766,38.455c0,24.318-18.238,40.733-57.301,45.598c-1.217-3.952-5.016-11.248-7.904-15.352c27.359-3.04,45.295-12.159,45.295-29.791c0-5.016-1.672-16.871-18.088-22.19c-6.688,15.199-16.871,29.335-28.727,39.519c0.607,1.976,1.367,3.647,2.127,5.167l-15.654,10.032c-0.76-1.521-1.52-3.192-2.129-5.017c-7.6,4.256-15.959,6.992-24.471,6.992c-13.375,0-22.189-8.512-22.189-22.647c0-20.975,16.111-37.542,37.693-46.357c-0.305-6.536-0.305-13.223-0.305-20.215c-11.398,0.304-23.711,0.608-29.789,0.456l-0.912-17.783c6.99,0.152,19.758,0.152,31.006,0.152c0.305-6.536,0.457-14.135,0.76-20.519l23.863,1.824c-0.305,1.52-1.52,2.736-4.104,3.04c-0.457,4.408-0.76,10.184-1.217,15.047c16.568-0.76,37.391-2.736,54.262-6.384l1.672,18.391c-16.719,3.04-38.605,4.56-56.846,5.168c-0.15,5.319-0.303,10.487-0.303,15.503c6.383-1.52,15.654-2.432,22.799-1.976c0.607-2.28,1.063-4.56,1.215-6.84L312.158,143.327z M255.77,198.044c-1.672-8.056-2.736-17.479-3.496-27.814c-12.008,5.927-20.215,15.199-20.215,25.382c0,8.664,6.535,8.36,8.512,8.209C245.281,203.668,250.449,201.539,255.77,198.044zM286.473,162.021c-2.129-0.304-10.033,0.305-16.871,2.128c0.455,7.6,0.91,14.591,1.975,20.671C277.504,178.589,282.672,170.686,286.473,162.021z"/></g></g></g></svg></span>
<strong>Translation</strong>
</span>
<span class="label label-status-{{ collector.countMissings ? 'error' : collector.countFallbacks ? 'warning' }} {{ collector.messages is empty ? 'disabled' }}">
<span class="icon">{{ include('@WebProfiler/Icon/translation.svg') }}</span>
<strong>Translation</strong>
{% if collector.countMissings or collector.countFallbacks %}
{% set error_count = collector.countMissings + collector.countFallbacks %}
<span class="count">
<span>{{ error_count }}</span>
</span>
{% endif %}
</span>
{% endblock %}
{% block panel %}
{% if collector.messages is empty %}
<h2>Translations</h2>
<p>
<em>No translations have been called.</em>
</p>
<div class="empty">
<p>No translations have been called.</p>
</div>
{% else %}
{{ block('panelContent') }}
{% endif %}
{% endblock %}
{% block panelContent %}
{% set filter = request.query.get('state', '-1') %}
{% set filterOptions = {
'-1': '',
(constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_DEFINED')): 'Defined messages',
(constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_MISSING')): 'Missing messages',
(constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK')): 'Fallback messages',
} %}
<h2>Translation Metrics</h2>
<h2>Translation Stats</h2>
<div class="metrics">
<div class="metric">
<span class="value">{{ collector.countdefines }}</span>
<span class="label">Defined messages</span>
</div>
<div class="metric">
<span class="value">{{ collector.countFallbacks }}</span>
<span class="label">Fallback messages</span>
</div>
<div class="metric">
<span class="value">{{ collector.countMissings }}</span>
<span class="label">Missing messages</span>
</div>
</div>
<h2>Translation Messages</h2>
{# sort translation messages in groups #}
{% set messages_defined, messages_missing, messages_fallback = [], [], [] %}
{% for message in collector.messages %}
{% if message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_DEFINED') %}
{% set messages_defined = messages_defined|merge([message]) %}
{% elseif message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_MISSING') %}
{% set messages_missing = messages_missing|merge([message]) %}
{% elseif message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK') %}
{% set messages_fallback = messages_fallback|merge([message]) %}
{% endif %}
{% endfor %}
<div class="sf-tabs">
<div class="tab">
<h3 class="tab-title">Defined <span class="badge">{{ messages_defined|length }}</span></h3>
<div class="tab-content">
<p class="help">
These messages are correctly translated into the given locale.
</p>
{% if messages_defined is empty %}
<div class="empty">
<p>None of the used translation messages are defined for the given locale.</p>
</div>
{% else %}
{{ helper.render_table(messages_defined) }}
{% endif %}
</div>
</div>
<div class="tab">
<h3 class="tab-title">Fallback <span class="badge">{{ messages_fallback|length }}</span></h3>
<div class="tab-content">
<p class="help">
These messages are not available for the given locale
but Symfony found them in the fallback locale catalog.
</p>
{% if messages_fallback is empty %}
<div class="empty">
<p>No fallback translation messages were used.</p>
</div>
{% else %}
{{ helper.render_table(messages_fallback) }}
{% endif %}
</div>
</div>
<div class="tab">
<h3 class="tab-title">Missing <span class="badge">{{ messages_missing|length }}</span></h3>
<div class="tab-content">
<p class="help">
These messages are not available for the given locale and cannot
be found in the fallback locales. Add them to the translation
catalogue to avoid Symfony outputting untranslated contents.
</p>
{% if messages_missing is empty %}
<div class="empty">
<p>There are no messages of this category.</p>
</div>
{% else %}
{{ helper.render_table(messages_missing) }}
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% macro render_table(messages) %}
<table>
<thead>
<tr>
<th>Locale</th>
<th>Domain</th>
<th>Times used</th>
<th>Message ID</th>
<th>Message Preview</th>
</tr>
</thead>
<tbody>
{% for message in messages %}
<tr>
<th>Defined messages</th>
<td><pre>{{ collector.countdefines }}</pre></td>
</tr>
<tr>
<th scope="col" style="width: 30%">Fallback messages</th>
<td scope="col" style="width: 60%"><pre>{{ collector.countFallbacks }}</pre></td>
</tr>
<tr>
<th>Missing messages</th>
<td><pre>{{ collector.countMissings }}</pre></td>
</tr>
<tr>
<th>Filter</th>
<td class="font-normal text-small">{{ message.locale }}</td>
<td class="font-normal text-small text-bold">{{ message.domain }}</td>
<td class="font-normal text-small">{{ message.count }}</td>
<td>
<form id="filter-form" action="" method="get" style="display: inline">
<input type="hidden" name="panel" value="translation">
<select id="filter" name="state" onchange="document.getElementById('filter-form').submit(); ">
{% for key,option in filterOptions %}
<option value="{{ key }}"{{ filter == key ? ' selected' : '' }}>{{ option }}</option>
{% endfor %}
</select>
<noscript>
<input type="submit" value="refresh">
</noscript>
</form>
</td>
</tr>
</tbody>
</table>
{{ message.id }}
<table>
<tr>
<th>State</th>
<th>Locale</th>
<th>Domain</th>
<th>Id</th>
<th>Message Preview</th>
</tr>
{% for message in collector.messages if message.state == filter or filter == '-1' %}
<tr>
<td><code>{{ translator.state(message) }}</code></td>
<td><code>{{ message.locale }}</code></td>
<td><code>{{ message.domain }}</code></td>
<td>
<code>{{ message.id }}</code>
{% if message.count > 1 %}<br><small style="color: gray;">(used {{ message.count }} times)</small>{% endif %}
{% if message.transChoiceNumber is not null %}<br><small style="color: gray;">(use pluralization)</small>{% endif %}
{% if message.transChoiceNumber is not null %}
<small class="newline">(pluralization is used)</small>
{% endif %}
{% if message.parameters|length > 0 %}
<div>
[<a href="#" onclick="return openParameters(this);" style="text-decoration: none;"
title="Toggle parameters display" data-target-id="parameters-{{ loop.index }}" >
<img alt="+" src="data:image/gif;base64,R0lGODlhEgASAMQTANft99/v+Ga44bHb8ITG52S44dXs9+z1+uPx+YvK6WC24G+944/M6W28443L6dnu+Ge54v/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5/vFID/DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7" style="display: inline; width: 12px; height: 12px;" />
<img alt="-" src="data:image/gif;base64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1+mC24IvK6ePx+Wa44dXs92+942e54o3L6W2844/M6dnu+P/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD/ER/wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO+hE0EoNAstEYGxG9heIhCADs=" style="display: none; width: 12px; height: 12px;" />
<span style="vertical-align:top">Parameters</span>
</a>]
<a class="newline text-small sf-toggle" data-toggle-selector="#parameters-{{ loop.index }}" data-toggle-alt-content="Hide parameters">Show parameters</a>
<div id="parameters-{{ loop.index }}" style="display: none;">
{% for parameters in message.parameters %}
{{ profiler_dump(parameters) }}
{% if not loop.last %}<br />{% endif %}
{% endfor %}
</div>
<div id="parameters-{{ loop.index }}" class="hidden">
{% for parameters in message.parameters %}
{{ profiler_dump(parameters) }}
{% if not loop.last %}<br />{% endif %}
{% endfor %}
</div>
{% endif %}
</td>
<td><code>{{ message.translation }}</code></td>
<td>{{ message.translation }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<script type="text/javascript">
function openParameters(link) {
"use strict";
var imgs = link.children,
target = link.getAttribute('data-target-id');
Sfjs.toggle(target, imgs[0], imgs[1]);
}
</script>
{% endblock %}
{% macro state(translation) %}
{% if translation.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK') %}
same as fallback
{% elseif translation.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_MISSING') %}
missing
{% endif %}
{% endmacro %}

View File

@ -31,58 +31,71 @@
{% 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 class="label">
<span class="icon">{{ include('@WebProfiler/Icon/twig.svg') }}</span>
<strong>Twig</strong>
</span>
</span>
{% endblock %}
{% block panel %}
{% if collector.templatecount %}
<h2>Twig Stats</h2>
{% if collector.templatecount == 0 %}
<h2>Twig</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>
<div class="empty">
<p>No Twig templates were rendered for this request.</p>
</div>
{% else %}
<h2>Twig Metrics</h2>
<div class="metrics">
<div class="metric">
<span class="value">{{ '%0.0f'|format(collector.time) }} <span class="unit">ms</span></span>
<span class="label">Render time</span>
</div>
<div class="metric">
<span class="value">{{ collector.templatecount }}</span>
<span class="label">Template calls</span>
</div>
<div class="metric">
<span class="value">{{ collector.blockcount }}</span>
<span class="label">Block calls</span>
</div>
<div class="metric">
<span class="value">{{ collector.macrocount }}</span>
<span class="label">Macro calls</span>
</div>
</div>
<p class="help">
Render time includes sub-requests rendering time (if any).
</p>
<h2>Rendered Templates</h2>
<table>
<tr>
<th scope="col">Template Name</th>
<th scope="col">Render Count</th>
</tr>
<thead>
<tr>
<th scope="col">Template Name</th>
<th scope="col">Render Count</th>
</tr>
</thead>
<tbody>
{% for template, count in collector.templates %}
<tr>
<td><code>{{ template }}</code></td>
<td><pre>{{ count }}</pre></td>
<td>{{ template }}</td>
<td class="font-normal">{{ count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h2>Rendering Call Graph</h2>
{{ collector.htmlcallgraph }}
{% else %}
<p><em>No Twig templates were rendered for this request.</em></p>
<div id="twig-dump">
{{ collector.htmlcallgraph }}
</div>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,3 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M11,5.1C11,3.4,9.6,2,7.9,2H5.1C3.4,2,2,3.4,2,5.1v12.9C2,19.6,3.4,21,5.1,21h2.9c1.7,0,3.1-1.4,3.1-3.1V5.1z M5.2,4h2.7C8.4,4,9,4.8,9,5.3V11H4V5.3C4,4.8,4.6,4,5.2,4z M22,5.1C22,3.4,20.6,2,18.9,2h-2.9C14.4,2,13,3.4,13,5.1v12.9c0,1.7,1.4,3.1,3.1,3.1h2.9c1.7,0,3.1-1.4,3.1-3.1V5.1z M16,4h2.8C19.4,4,20,4.8,20,5.3V8h-5V5.3C15,4.8,15.5,4,16,4z"/>
</svg>

After

Width:  |  Height:  |  Size: 532 B

View File

@ -0,0 +1,11 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M19.2,20.8c0.4,0.7,0.1,1.6-0.6,2c-0.2,0.1-0.5,0.2-0.7,0.2c-0.5,0-1-0.3-1.3-0.8l-3.7-6.7
c-0.3,0.1-0.7,0.1-1,0.1c-0.3,0-0.6,0-0.9-0.1l-3.7,6.7C6.9,22.7,6.4,23,5.8,23c-0.2,0-0.5-0.1-0.7-0.2c-0.7-0.4-1-1.3-0.6-2
l3.8-6.9c-0.5-0.7-0.9-1.6-0.9-2.6C7.5,8.9,9.4,7,11.8,7s4.3,1.9,4.3,4.3c0,0.9-0.3,1.8-0.8,2.5L19.2,20.8z M5.2,11
C5.2,11,5.2,11,5.2,11c0.6,0,1-0.3,1-0.8c0-2.1,1.6-3.8,3.7-4.1c0.5-0.1,0.9-0.6,0.8-1.2C10.6,4.4,10.1,4,9.6,4
c-3.1,0.5-5.3,3-5.3,6.1C4.2,10.7,4.7,11,5.2,11z M13.6,6c2.1,0.3,3.7,2.1,3.8,4.2c0,0.5,0.5,0.8,1,0.8c0,0,0,0,0,0
c0.6,0,1-0.3,1-0.8c0-3.1-2.4-5.6-5.5-6.1c-0.5-0.1-1.1,0.3-1.1,0.8C12.6,5.5,13,5.9,13.6,6z M9,3c0.5-0.1,0.9-0.6,0.8-1.1
C9.7,1.3,9.2,1,8.7,1.1C4.5,1.8,1.4,5.5,1.3,9.8c0,0.6,0.4,1.2,1,1.2c0,0,0,0,0,0c0.5,0,1-0.6,1-1.2C3.3,6.5,5.7,3.5,9,3z M14.7,1
c-0.5-0.1-1.1,0.3-1.1,0.9S13.9,3,14.4,3c3.3,0.5,5.8,3.4,5.8,6.8c0,0.5,0.5,1.2,1,1.2c0,0,0,0,0,0c0.6,0,1-0.7,1-1.2
C22.2,5.5,19,1.6,14.7,1z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,15 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M23.5,9.5c0-0.2-1.2,0.2-1.6,0.2c0,0,0,0,0,0c0.1-0.3,0.3-0.6,0.4-0.8C23,7.4,22,6.6,21,7.5
c-0.4,0.4,0,1.1,0,1.8c0,0.1,0,0.2,0,0.3c-0.2-0.1-0.4-0.1-0.6-0.3c-0.5-0.8-1.1-0.2-1.1,0c0,0.3,0.7,0.9,1.1,0.9c0.1,0,0.1,0,0.2,0
c0,0.1,0,0.3,0,0.5c0,0.7-0.8,1.1-1.7,1.2V9.1c0-4.3-3.3-6.4-6.9-6.4c-3.5,0-6.9,2-6.9,6.4v2.8c-0.9-0.2-1.8-0.5-1.8-1.2
c0-0.1,0-0.1,0-0.2c0.1,0,0.1,0,0.2,0c0.5,0,1.1-0.2,1.1-0.4C4.8,8.7,4,9.6,3.5,9.6c-0.1,0-0.2,0-0.3,0c0-0.1,0.1-0.2,0.1-0.4
c0-0.5,1.2-1.7-0.8-1.9C2.1,7.3,2,8.2,2.1,8.6C2.3,9,2.4,9.5,2.5,9.8C2.4,9.6,2.2,9.6,2,9.5C1.8,9.3,0.4,7.6,0.1,9.5
c-0.1,1.1,1,1.2,1.9,1c0.1,0,0.2-0.1,0.3-0.1c-0.1,0.3-0.2,0.7-0.2,1.2c0,1.3,1.5,1.6,2.9,1.7c0,1.7,0,5.2,0,5.2
c0,1.6,0.5,2.8,2.2,2.8c1.8,0,2.4-1.3,2.4-2.9c0,1.6,0.6,2.9,2.3,2.9s2.3-2.2,2.3-2.8c0,1.7,0.7,2.8,2.4,2.8c1.7,0,2.2-1.2,2.2-2.9
v-5.1c1.4-0.1,2.9-0.4,2.9-1.7c0-0.4-0.1-0.7-0.1-1c0.4,0.5,1.1,0.8,1.7,0.5C24.5,10.4,23.5,9.7,23.5,9.5z M6.8,8.4
c0-1.5,1-2.5,2.3-2.5c1.3,0,2.3,1.1,2.3,2.5c0,1.4-1,2.6-2.2,2.6c0.6,0,1.1-0.5,1.1-1.2c0-0.6-0.5-1.2-1.2-1.2
c-0.6,0-1.2,0.5-1.2,1.2c0,0.6,0.5,1.2,1.2,1.2c0,0,0,0,0,0C7.8,11,6.8,9.9,6.8,8.4z M11.9,15.9c-2.9-0.1-3.1-1.6-3.1-2.5
c0-0.9,1.7-0.3,3.2-0.3c1.5,0,3.1-0.7,3.1,0.2C15.1,14.3,14.3,16,11.9,15.9z M15,11c0.6-0.1,1-0.6,1-1.2c0-0.6-0.5-1.2-1.2-1.2
c-0.6,0-1.2,0.5-1.2,1.2c0,0.6,0.5,1.2,1.1,1.2c0,0,0,0,0,0c-1.3,0-2.3-1.2-2.3-2.6c0-1.5,1-2.5,2.3-2.5c1.3,0,2.3,1.1,2.3,2.5
C17.1,9.8,16.2,10.9,15,11z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,5 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="28" viewBox="0 0 12 12" enable-background="new 0 0 12 12" xml:space="preserve">
<path fill="#B0413E" d="M10.4,8.4L8,6l2.4-2.4c0.8-0.8,0.7-1.6,0.2-2.2C10,0.9,9.2,0.8,8.4,1.6L6,4L3.6,1.6C2.8,0.8,2,0.9,1.4,1.4
C0.9,2,0.8,2.8,1.6,3.6L4,6L1.6,8.4C0.8,9.2,0.9,10,1.4,10.6c0.6,0.6,1.4,0.6,2.2-0.2L6,8l2.4,2.4c0.8,0.8,1.6,0.7,2.2,0.2
C11.1,10,11.2,9.2,10.4,8.4z"/>
</svg>

After

Width:  |  Height:  |  Size: 454 B

View File

@ -0,0 +1,16 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M15.8,6.4h-1.1c0,0-0.1,0.1-0.1,0l0.8-0.7c0.5-0.5,0.5-1.3,0-1.9l-1.4-1.4c-0.5-0.5-1.4-0.5-1.9,0l-0.6,0.8
c-0.1,0,0,0,0-0.1V2.1c0-0.8-1-1.4-1.8-1.4h-2c-0.8,0-1.9,0.6-1.9,1.4v1.1c0,0,0.1,0.1,0.1,0.1L5.1,2.5c-0.5-0.5-1.3-0.5-1.9,0
L1.8,3.9c-0.5,0.5-0.5,1.4,0,1.9l0.8,0.6c0,0.1,0,0-0.1,0H1.4C0.7,6.4,0,7.5,0,8.2v2c0,0.8,0.7,1.8,1.4,1.8h1.2c0,0,0.1-0.1,0.1-0.1
l-0.8,0.7c-0.5,0.5-0.5,1.3,0,1.9L3.3,16c0.5,0.5,1.4,0.5,1.9,0l0.6-0.8c0.1,0-0.1,0-0.1,0.1v1.2c0,0.8,1.1,1.4,1.9,1.4h2
c0.8,0,1.8-0.6,1.8-1.4v-1.2c0,0-0.1-0.1,0-0.1l0.7,0.8c0.5,0.5,1.3,0.5,1.9,0l1.4-1.4c0.5-0.5,0.5-1.4,0-1.9L14.6,12
c0-0.1,0,0.1,0.1,0.1h1.1c0.8,0,1.3-1.1,1.3-1.8v-2C17.1,7.5,16.5,6.4,15.8,6.4z M8.6,13c-2.1,0-3.8-1.7-3.8-3.8
c0-2.1,1.7-3.8,3.8-3.8c2.1,0,3.8,1.7,3.8,3.8C12.3,11.3,10.6,13,8.6,13z"/>
<path fill="#AAAAAA" d="M22.3,15.6l-0.6,0.2c0,0,0,0.1,0,0l0.3-0.5c0.2-0.4,0-0.8-0.4-1l-1-0.4c-0.4-0.2-0.8,0-1,0.4l-0.1,0.5
c0,0,0,0,0,0l-0.2-0.6c-0.2-0.4-0.8-0.5-1.2-0.3l-1.1,0.4c-0.4,0.2-0.8,0.7-0.7,1.1l0.2,0.6c0,0,0.1,0,0.1,0l-0.5-0.3
c-0.4-0.2-0.8,0-1,0.4l-0.4,1c-0.2,0.4,0,0.8,0.4,1l0.5,0.1c0,0,0,0,0,0l-0.6,0.2c-0.4,0.2-0.5,0.8-0.4,1.2l0.4,1.1
c0.2,0.4,0.7,0.8,1.1,0.7l0.6-0.2c0,0,0-0.1,0,0l-0.3,0.5c-0.2,0.4,0,0.8,0.4,1l1,0.4c0.4,0.2,0.8,0,1-0.4l0.1-0.5c0,0,0,0,0,0
l0.2,0.6c0.2,0.4,0.9,0.5,1.2,0.3l1.1-0.4c0.4-0.2,0.8-0.7,0.6-1.1l-0.2-0.6c0,0-0.1,0,0,0l0.5,0.3c0.4,0.2,0.8,0,1-0.4l0.4-1
c0.2-0.4,0-0.8-0.4-1l-0.5-0.1c0,0,0,0,0,0l0.6-0.2c0.4-0.2,0.5-0.8,0.3-1.2l-0.4-1.1C23.2,15.9,22.7,15.5,22.3,15.6z M19.9,20.5
c-1.1,0.4-2.3-0.1-2.7-1.2c-0.4-1.1,0.1-2.3,1.2-2.7c1.1-0.4,2.3,0.1,2.7,1.2C21.5,18.9,21,20.1,19.9,20.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,6 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M13,3v18c0,1.1-0.9,2-2,2s-2-0.9-2-2V3c0-1.1,0.9-2,2-2S13,1.9,13,3z M23.2,4.6l-1.8-1.4
C21.2,2.9,20.8,3,20.4,3h-1.3H14v2.1V8h5.1h1.3c0.4,0,0.8-0.3,1.1-0.5l1.8-1.6C23.6,5.6,23.6,4.9,23.2,4.6z M19.5,9.4
C19.2,9.1,18.8,9,18.4,9h-0.3H14v2.6V14h4.1h0.3c0.4,0,0.8-0.1,1.1-0.3l1.8-1.5c0.4-0.3,0.4-0.9,0-1.3L19.5,9.4z M3.5,7
C3.1,7,2.8,7,2.5,7.3L0.7,8.8c-0.4,0.3-0.4,0.9,0,1.3l1.8,1.6C2.8,11.9,3.1,12,3.5,12h0.3H8V9.4V7H3.9H3.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 624 B

View File

@ -0,0 +1,7 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<path fill="#AAAAAA" d="M11.61,0.357c-4.4,0-7.98,3.58-7.98,7.98c0,1.696,0.526,3.308,1.524,4.679l-4.374,4.477
c-0.238,0.238-0.369,0.554-0.369,0.891c0,0.336,0.131,0.653,0.369,0.891c0.238,0.238,0.554,0.369,0.891,0.369
c0.336,0,0.653-0.131,0.893-0.371l4.372-4.475c1.369,0.996,2.98,1.521,4.674,1.521c4.4,0,7.98-3.58,7.98-7.98
S16.01,0.357,11.61,0.357z M17.07,8.337c0,3.011-2.449,5.46-5.46,5.46c-3.011,0-5.46-2.449-5.46-5.46s2.449-5.46,5.46-5.46
C14.62,2.877,17.07,5.326,17.07,8.337z"/>
</svg>

After

Width:  |  Height:  |  Size: 682 B

View File

@ -0,0 +1,5 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="28" viewBox="0 0 12 12" enable-background="new 0 0 12 12" xml:space="preserve">
<path fill="#5E976E" d="M12,3.1c0,0.4-0.1,0.8-0.4,1.1L5.9,9.8c-0.3,0.3-0.6,0.4-1,0.4c-0.4,0-0.7-0.1-1-0.4L0.4,6.3
C0.1,6,0,5.6,0,5.2c0-0.4,0.2-0.7,0.4-0.9C0.6,4,1,3.9,1.3,3.9c0.4,0,0.8,0.1,1.1,0.4l2.5,2.5l4.7-4.7c0.3-0.3,0.7-0.4,1-0.4
c0.4,0,0.7,0.2,0.9,0.4C11.8,2.4,12,2.7,12,3.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 462 B

View File

@ -1,10 +1,7 @@
{% if token is not empty %}
<div class="search import clearfix" id="adminBar">
<h3>
<img style="margin: 0 5px 0 0; vertical-align: middle; height: 16px" width="16" height="16" alt="Import" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADo0lEQVR42u2XS0hUURjHD5njA1oYbXQ2MqCmIu2iEEISUREEEURxFB8ovt+DEsLgaxBRQQeUxnQ0ZRYSQasgiDaFqxAy2jUtCjdCoEjFwHj6/+F+dbvN6PQAN37wm++c7/z/35x7uPcOo7TW58rFBs59A7GGQ51XBAIBlZmZuYOhE1zm/A/4PxvY3NwMO53OYEJCgp+nccqXXQc94D54boAxalyLNayNtra2NJmbmzvOyMj4cRqoKYK4AsZzc3Nft7e3f5qZmTnCpk8Ix6xxjRpDGzmkUU5Ozuu2trZP09PTR+vr6ycbGxtaWFtbC9fU1AQTExPdmNNzLSUlZXt4ePhANNGghlp6lDWkkcvlOsCX6LNYXV0N8BTS0tK2cDJfWIsFaumhV0lIIxzXl5WVFX0aPp8vhDwJbMnJyc6JiYkji8YP7oI4YowfmDX00KskOHG73UfLy8vahB/cBXFSW1pa2kPOA7RdqqysfGtaCyOXA2VGgmvUiJ5e9lD8qKioeOv1ejVZXFwMI5eLEWOFWgh5Etg4J0lJSTdwYiHxLSwseFi3Yg5qRE8veyh+TE1Nhebn5zWZnZ31mE2okTxmM6WlpS7xeDyeQ2Qb61bMQQ214mMPVVxc7MJuNBkfHz9EtplNmEcET4JPfL29va+i6azR19f3UnzV1dUrqqqqyocT0KSzs/OV1YB6ROrr67fF19TU9DSazhp1dXXPxdfS0vJQNTY2+sfGxjSpra19YTWgHhHs/pn40OhRNJ0lLuON+kF8ra2tY9yAe3R0VBMc6wfr84n6b1BDrfiam5snImgczObAq7ylv7//q/hGRkbuqMHBwTt4Q2nS3d39jSKzCfXfoKarq+ur+NhD1owLcNrt9h3OTXGrqKgoKJ6hoaFD5DhuIA43xiGyJoWFhUGKxYXaL3CNGtH39PR8Zg9jzREfH+8vKCgI4krDRu0GcGVnZ78ZGBg4ER/Wf+4OVzOMRhrwFE6ysrLe0EQzaopII65RI3p478lVp6am7uDmPJY11F44HI7dsrKyfc5Nnj1km5Lo6Oiw4cdnD1kLJSUl++np6btsQjhmzayB5x29uGp3fn5+EPMw66eBX8b3yHZlDdyRdtzN75F1LED7kR6gMA7E6HsMrqpogbv5KngM9Bk8MbTKwAYmQSiCdhd4wW0VazQ0NNwEXrALNDHGS+A2UFHIA3smj/rX4JvrT7GBSRDi/J8Db8e/JY/5jLj4Y3KxgfPfwHc53iL+IQDMOgAAAABJRU5ErkJggg==">
Admin
</h3>
<div id="sidebar-admin">
<h3>Administration tools</h3>
<div style="margin-bottom: 10px">&#187;&#160;<a href="{{ path('_profiler_purge', { 'token': token }) }}">Purge</a></div>
<a href="{{ path('_profiler_purge', { token: token }) }}">Delete all profiles</a>
</div>
{% endif %}

View File

@ -1,15 +1,19 @@
<table {% if class is defined %}class='{{ class }}'{% endif %} >
<table class="{{ class|default('') }}">
<thead>
<tr>
<th scope="col" style="width: 25%">Key</th>
<th scope="col" style="width: 75%">Value</th>
<th scope="col" class="key">{{ labels is defined ? labels[0] : 'Key' }}</th>
<th scope="col">{{ labels is defined ? labels[1] : 'Value' }}</th>
</tr>
</thead>
<tbody>
{% for key in bag.keys|sort %}
<tr>
<th>{{ key }}</th>
<td><pre>{{ profiler_dump(bag.get(key)) }}</pre></td>
<td>{{ profiler_dump(bag.get(key)) }}</td>
</tr>
{% else %}
<tr>
<td colspan="2">(no data)</td>
</tr>
{% endfor %}
</tbody>

View File

@ -3,19 +3,14 @@
<head>
<meta charset="{{ _charset }}" />
<meta name="robots" content="noindex,nofollow" />
<title>{% block title 'Profiler' %}</title>
<link rel="icon" type="image/x-icon" sizes="16x16" href="data:image/ico;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABMLAAATCwAAAAAAAAAAAAAAAAAAAAAAADIvMQAyLzEIMi8xSzEuMKoyLzHkMi8x/TIvMf0yLzHlMi8xrDIvMU4yLzEJMi8xAAAAAAAAAAAAAAAAADIvMQAyLzEYMS4wkTMwMu45Njj/MS4w/zEuMP8yLzH/Mi8x/zIvMf8yLzHvMi8xlDIvMRkyLzEAAAAAADIvMQAyLzEXMS4wrTk2OPyVk5T7kI6P/nl3ef8+Oz3/MS4w/zIvMf8yLzH/Mi8x/zIvMf4yLzGxMi8xGjIvMQAyLzEGMi8xkDEuMP4/PD79wcDA+oB+gP6Ni4z/paOk/zk2OP8xLjD/Mi8x/zIvMf8yLzH/Mi8x/zIvMZQyLzEIMi8xSTIvMewyLzH/MS4w/z06PP81MjT+TktN/93c3f97eXv/MC0v/zIvMf8yLzH/Mi8x/zIvMf8yLzHuMi8xTzIvMaUyLzH/Mi8x/0lHSf9kYmP/XFpb/zs4Ov/DwsL+ycjI/zs4Ov8xLjD/Mi8x/zIvMf8yLzH/Mi8x/zIvMawyLzHfMC0v/1tYWv+opqf/YV5g/8bFxf96eHn+m5qb/u7u7v9WVFX/MC0v/zIvMf8yLzH/Mi8x/zIvMf8yLzHkMi8x+jAtL/9iYGH/mZiZ/2dlZv/p6On/oJ+g/np4ev/6+vr/dXN1/y0qLP8xLjD/Mi8x/zIvMf8yLzH/Mi8x/DIvMfoyLzH/MzAy/0A+QP7JyMj85eXl/1tYWv9XVVf/8fDx/6qpqv9ZV1j/Q0BC/zIvMf8yLzH/Mi8x/zIvMfwyLzHeMi8x/zEuMP8/PD762dnZ9JWTlP81MjT/ZmRm/+Dg4P/DwsP/YV5g/6Wkpf9BPkD/MS4w/zIvMf8yLzHjMi8xozIvMf8yLzH/Mi8x/nZ0dv2amJn4dXN0+V5bXf+Pjo//0tLS/0hFR/9vbG7/Ozg6/zEuMP8yLzH/Mi8xqTIvMUcyLzHrMi8x/zIvMf8xLjD/Ozg6/Do3OfwwLS//REFD/728vP9nZWb/TktN/4mIif05Nzn/Mi8x7jMwMkwyLzEGMi8xjDIvMf4yLzH/Mi8x/zIvMf8yLzH/Mi8x/zAtL/9XVFb/goGC+Hx6e+6qqanwOzg6/DMwMpJDQEIIMi8xADIvMRUyLzGrMi8x/jIvMf8yLzH/Mi8x/zIvMf8yLzH/MS4w/zg2N/xBPkD3OTY4/DIvMa8yLzEYMi8xAAAAAAAyLzEAMi8xGDIvMY0yLzHqMi8x/zIvMf8yLzH/Mi8x/zIvMf8yLzH/MS4w7DEuMJEyLzEaMi8xAAAAAAAAAAAAAAAAADIvMQAyLzEGMi8xQzIvMZ4yLzHdMi8x+jIvMfoyLzHeMi8xoDIvMUUyLzEGMi8xAAAAAAAAAAAA4AcAAMADAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAADAAwAA4AcAAA==">
<style>
{% include '@WebProfiler/Profiler/body.css.twig' %}
</style>
<title>Symfony Profiler</title>
<link rel="icon" type="image/x-icon" sizes="16x16" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFEUlEQVR4AZVXA4wm2RMf27bXDM/+3/+sYBGfrbVtezc6BWtzfPbYXtvDL9906t6v0vWl05me7q1JzXuvvu4yXnvZgJ9hH6bwZYXLFR739vauUGuDwhq1L1N4Uv/tRYUhFjwcg49hn6aYr1V4TiGp86CoP9Oh1tV414KnM6t9fHymKUZ3DAI0hW4b1AyK3lE8phh5OxWeoJgUGhi5mLm95YzBwcHuhIQEV1JSEoWGhoKWHxYWFmenhJ/B5W0GwZpDt5Ovry9lZWWRyWOu5ORk7JsUpogsq5gnmISTU+HKQoLFQv/qq6/os88+I+EVFRUlSsRZ5oRiVmwlXMWShQkahUdERJCfnx/vd+3aRTU1NXTixAmqrq6mK1eu0PTp05mnrmD+QK6XhLO0XP2O2FJAQICRjjMU4P1PP/1EfX19NGfOHM8Z0N7ezueQkBBXYGAgSWIaQ5Em2T5QzFNSUig9PV3OHOe4uDjZ87p//34C7Nm7x/NcRUUFAX799Vec8Y7m7+8Pz92SfBDXr7VwPYRbxn/MmDG8Tps2jQBd3V30/PPPe35/6qmnaPXq1TR69Gg+h4eHiwwosdLT4dBkQDSXWmJiIq/vv/8+/fvvv3ThwgWqr6+n/Px8oyCmAerq6jy03Nxc2Yv7ySSjQzrmi4i92fVpaWlYOZ79/f2MW7dtpSlTptDp06epo6ODPvroI850ASiGdyZOnEjXrl2jyspKT4XA9cgjkaPL/D8UWG62HokieyQQoKSkRGiMs2bNotraWmprayOBNWvWyO+scGdnp5zF/WYvLEb8TwpRykp1MV7feust6uzqJMD169fpueeeY/rDDz/MKzzgdrsJoGkaffvtt/TFF19wQsIDmzZtssojt+6Fo1CgzKiAvAB3DRs2jAULtLS0eErPGB5Ad3c3lZaWUnFxMfeAd955h5+JjY3FaqXAPwhBnRCNySK4b98+Aoilv/z6i/zGggSk1g0opWupAMvGP91yt96zadWqVdTc3Ezz58/31LOAy+US6zgHBP766y+mDR8+HBUgFWSnQI2EAFnqlpcaGxsJIFkMN8L9AnPnzmX6jRs3SACeAi0vL888JwYPgTEJpauhnADo6/LSgQMHCHD37l2Cp15//XXq7eslgKb+Fi1exM9lZmbaCDclIcpQQhATE4OVsrOzuamg+cyePZuzG64Hrlu3jp9ZuWolCdy+fZueeOIJpkdHR1sLHqgM0Yh0bTRz1m7fvp2KiopYkYKCApo8ebLZIwzlFeXSOXEnsLPe2Ij+p5DbYYdOdOtDQ0rNjFya5sTcsGGDcTDZoXTcNoVBMoxWyzDS2yXmOyeUtGSskmDjx4/nRgPAfBDmMpZtUIbRcsi2GsfSD2QYyd2OcdmyZSSwdu1apuXk5GB16v4bak0yX0imyIUEgwNovFTglhMZGcm0srIy43zAVUxuTLbW4xn17Fci23wly9dngUummrTaixcvMpOtW7fiiBwQpqKYU9efHuxDJE5hC9wvL9TW1RLg+PHjPGTQ8wsLC4WpDC5Y5UR4k5qKMSLT6lqeAiX0nuAaMmSI9sMPP9CZM2foyJEj9O677wpTVIuTjidNp0HibvttoH9E5OMqbWKkSaNSlojldoLF7TEP+nUEmKI62y1kOBINbVaNarcI0PuGGUlHyfYvLHg7/jhFSFYqZh0P8KHSptd5ksOPU3tvqAEUot/hFmOIYJLp87wGe9Dwm95eg5xa/R8G6d8U5EcFhwAAAABJRU5ErkJggg==">
{% block head %}
<style>
{% include '@WebProfiler/Profiler/profiler.css.twig' %}
{{ include('@WebProfiler/Profiler/profiler.css.twig') }}
</style>
{% endblock %}
<style>
{% include '@WebProfiler/Profiler/toolbar.css.twig' with { 'position': 'top', 'floatable': false } %}
</style>
</head>
<body>
{% block body '' %}

View File

@ -1,7 +1,25 @@
<script>/*<![CDATA[*/
{# Caution: the contents of this file are processed by Twig before loading
them as JavaScript source code. Always use '/*' comments instead
of '//' comments to avoid impossible-to-debug side-effects #}
Sfjs = (function() {
"use strict";
var classListIsSupported = 'classList' in document.documentElement;
if (classListIsSupported) {
var hasClass = function (el, cssClass) { return el.classList.contains(cssClass); };
var removeClass = function(el, cssClass) { el.classList.remove(cssClass); };
var addClass = function(el, cssClass) { el.classList.add(cssClass); };
var toggleClass = function(el, cssClass) { el.classList.toggle(cssClass); };
} else {
var hasClass = function (el, cssClass) { return el.className.match(new RegExp('\\b' + cssClass + '\\b')); };
var removeClass = function(el, cssClass) { el.className = el.className.replace(new RegExp('\\b' + cssClass + '\\b'), ' '); };
var addClass = function(el, cssClass) { if (!hasClass(el, cssClass)) { el.className += " " + cssClass; } };
var toggleClass = function(el, cssClass) { hasClass(el, cssClass) ? removeClass(el, cssClass) : addClass(el, cssClass); };
}
var noop = function() {},
collectionToArray = function (collection) {
@ -46,22 +64,6 @@
xhr.send(payload || '');
},
hasClass = function(el, klass) {
return el.className && el.className.match(new RegExp('\\b' + klass + '\\b'));
},
removeClass = function(el, klass) {
if (el.className) {
el.className = el.className.replace(new RegExp('\\b' + klass + '\\b'), ' ');
}
},
addClass = function(el, klass) {
if (!hasClass(el, klass)) {
el.className += " " + klass;
}
},
getPreference = function(name) {
if (!window.localStorage) {
return null;
@ -255,6 +257,8 @@
addClass: addClass,
toggleClass: toggleClass,
getPreference: getPreference,
setPreference: setPreference,
@ -298,7 +302,118 @@
}
return this;
},
createTabs: function() {
var tabGroups = document.querySelectorAll('.sf-tabs');
/* create the tab navigation for each group of tabs */
for (var i = 0; i < tabGroups.length; i++) {
var tabs = tabGroups[i].querySelectorAll('.tab');
var tabNavigation = document.createElement('ul');
tabNavigation.className = 'tab-navigation';
for (var j = 0; j < tabs.length; j++) {
var tabId = 'tab-' + i + '-' + j;
var tabTitle = tabs[j].querySelector('.tab-title').innerHTML;
var tabNavigationItem = document.createElement('li');
tabNavigationItem.setAttribute('data-tab-id', tabId);
if (j == 0) { Sfjs.addClass(tabNavigationItem, 'active'); }
if (Sfjs.hasClass(tabs[j], 'disabled')) { Sfjs.addClass(tabNavigationItem, 'disabled'); }
tabNavigationItem.innerHTML = tabTitle;
tabNavigation.appendChild(tabNavigationItem);
var tabContent = tabs[j].querySelector('.tab-content');
tabContent.parentElement.setAttribute('id', tabId);
}
tabGroups[i].insertBefore(tabNavigation, tabGroups[i].firstChild);
}
/* display the active tab and add the 'click' event listeners */
for (i = 0; i < tabGroups.length; i++) {
tabNavigation = tabGroups[i].querySelectorAll('.tab-navigation li');
for (j = 0; j < tabNavigation.length; j++) {
tabId = tabNavigation[j].getAttribute('data-tab-id');
document.getElementById(tabId).querySelector('.tab-title').className = 'hidden';
if (Sfjs.hasClass(tabNavigation[j], 'active')) {
document.getElementById(tabId).className = 'block';
} else {
document.getElementById(tabId).className = 'hidden';
}
tabNavigation[j].addEventListener('click', function(e) {
var activeTab = e.target || e.srcElement;
/* needed because when the tab contains HTML contents, user can click */
/* on any of those elements instead of their parent '<li>' element */
while (activeTab.tagName.toLowerCase() !== 'li') {
activeTab = activeTab.parentNode;
}
for (var k = 0; k < tabNavigation.length; k++) {
var tabId = tabNavigation[k].getAttribute('data-tab-id');
document.getElementById(tabId).className = 'hidden';
Sfjs.removeClass(tabNavigation[k], 'active');
}
Sfjs.addClass(activeTab, 'active');
var activeTabId = activeTab.getAttribute('data-tab-id');
document.getElementById(activeTabId).className = 'block';
});
}
}
},
createToggles: function() {
var toggles = document.querySelectorAll('.sf-toggle');
for (var i = 0; i < toggles.length; i++) {
var elementSelector = toggles[i].getAttribute('data-toggle-selector');
var element = document.querySelector(elementSelector);
Sfjs.addClass(element, 'sf-toggle-content');
if (toggles[i].hasAttribute('data-toggle-initial') && toggles[i].getAttribute('data-toggle-initial') == 'display') {
Sfjs.addClass(element, 'sf-toggle-visible');
} else {
Sfjs.addClass(element, 'sf-toggle-hidden');
}
Sfjs.addEventListener(toggles[i], 'click', function(e) {
var toggle = e.target || e.srcElement;
var element = document.querySelector(toggle.getAttribute('data-toggle-selector'));
Sfjs.toggleClass(element, 'sf-toggle-hidden');
Sfjs.toggleClass(element, 'sf-toggle-visible');
/* the toggle doesn't change its contents when clicking on it */
if (!toggle.hasAttribute('data-toggle-alt-content')) {
return;
}
if (!toggle.hasAttribute('data-toggle-original-content')) {
toggle.setAttribute('data-toggle-original-content', toggle.innerHTML);
}
var currentContent = toggle.innerHTML;
var originalContent = toggle.getAttribute('data-toggle-original-content');
var altContent = toggle.getAttribute('data-toggle-alt-content');
toggle.innerHTML = currentContent !== altContent ? altContent : originalContent;
e.preventDefault();
});
}
}
}
};
})();
Sfjs.addEventListener(window, 'load', function() {
Sfjs.createTabs();
Sfjs.createToggles();
});
/*]]>*/</script>

View File

@ -1,137 +0,0 @@
/*
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.com/yui/license.html
version: 3.1.2
build: 56
*/
.sf-reset div,.sf-reset dl,.sf-reset dt,.sf-reset dd,.sf-reset ul,.sf-reset ol,.sf-reset li,.sf-reset h1,.sf-reset h2,.sf-reset h3,.sf-reset h4,.sf-reset h5,.sf-reset h6,.sf-reset pre,.sf-reset code,.sf-reset form,.sf-reset fieldset,.sf-reset legend,.sf-reset input,.sf-reset textarea,.sf-reset p,.sf-reset blockquote,.sf-reset th,.sf-reset td{margin:0;padding:0;}.sf-reset table{border-collapse:collapse;border-spacing:0;}.sf-reset fieldset,.sf-reset img{border:0;}.sf-reset address,.sf-reset caption,.sf-reset cite,.sf-reset code,.sf-reset dfn,.sf-reset em,.sf-reset strong,.sf-reset th,.sf-reset var{font-style:normal;font-weight:normal;}.sf-reset li{list-style:none;}.sf-reset caption,.sf-reset th{text-align:left;}.sf-reset h1,.sf-reset h2,.sf-reset h3,.sf-reset h4,.sf-reset h5,.sf-reset h6{font-size:100%;font-weight:normal;}.sf-reset q:before,.sf-reset q:after{content:'';}.sf-reset abbr,.sf-reset acronym{border:0;font-variant:normal;}.sf-reset sup{vertical-align:text-top;}.sf-reset sub{vertical-align:text-bottom;}.sf-reset input,.sf-reset textarea,.sf-reset select{font-family:inherit;font-size:inherit;font-weight:inherit;}.sf-reset input,.sf-reset textarea,.sf-reset select{font-size:100%;}.sf-reset legend{color:#000;}
.sf-reset abbr {
border-bottom: 1px dotted #000;
cursor: help;
}
.sf-reset p {
font-size: 14px;
line-height: 20px;
padding-bottom: 20px;
}
.sf-reset strong {
color: #313131;
font-weight: bold;
}
.sf-reset a {
color: #6c6159;
}
.sf-reset a img {
border: none;
}
.sf-reset a:hover {
text-decoration: underline;
}
.sf-reset em {
font-style: italic;
}
.sf-reset h2,
.sf-reset h3 {
font-weight: bold;
}
.sf-reset h1 {
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 20px;
color: #313131;
word-break: break-all;
}
.sf-reset li {
padding-bottom: 10px;
}
.sf-reset .block {
-moz-border-radius: 16px;
-webkit-border-radius: 16px;
border-radius: 16px;
margin-bottom: 20px;
background-color: #FFFFFF;
border: 1px solid #dfdfdf;
padding: 40px 50px;
}
.sf-reset h2 {
font-size: 16px;
font-family: Arial, Helvetica, sans-serif;
}
.sf-reset li a {
background: none;
color: #868686;
text-decoration: none;
}
.sf-reset li a:hover {
background: none;
color: #313131;
text-decoration: underline;
}
.sf-reset ol {
padding: 10px 0;
}
.sf-reset ol li {
list-style: decimal;
margin-left: 20px;
padding: 2px;
padding-bottom: 20px;
}
.sf-reset ol ol li {
list-style-position: inside;
margin-left: 0;
white-space: nowrap;
font-size: 12px;
padding-bottom: 0;
}
.sf-reset li .selected {
background-color: #ffd;
}
.sf-button {
display: -moz-inline-box;
display: inline-block;
text-align: center;
vertical-align: middle;
border: 0;
background: transparent none;
text-transform: uppercase;
cursor: pointer;
font: bold 11px Arial, Helvetica, sans-serif;
}
.sf-button span {
text-decoration: none;
display: block;
height: 28px;
float: left;
}
.sf-button .border-l {
text-decoration: none;
display: block;
height: 28px;
float: left;
padding: 0 0 0 7px;
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQtJREFUeNpiPHnyJAMakARiByDWYEGT8ADiYGVlZStubm5xlv///4MEQYoKZGRkQkRERLRYWVl5wYJQyXBZWdkwCQkJUxAHKgaWlAHSLqKiosb//v1DsYMFKGCvoqJiDmQzwXTAJYECulxcXNLoumCSoszMzDzoumDGghQwYZUECWIzkrAkSIIGOmlkLI10AiX//P379x8jIyMTNmPf/v79+ysLCwsvuiQoNi5//fr1Kch4dAyS3P/gwYMTQBP+wxwHw0xA4gkQ73v9+vUZdJ2w1Lf82bNn4iCHCQoKasHsZw4ODgbRIL8c+/Lly5M3b978Y2dn5wC6npkFLXnsAOKLjx49AmUHLYAAAwBoQubG016R5wAAAABJRU5ErkJggg==) no-repeat top left;
}
.sf-button .border-r {
padding: 0 7px 0 0;
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR1JREFUeNpiPHnyZCMDA8MNID5gZmb2nAEJMH7//v3N169fX969e/cYkL8WqGAHXPLv37//QYzfv39/fvPmzbUnT56sAXInmJub/2H5/x8sx8DCwsIrISFhDmQyPX78+CmQXs70798/BmQsKipqBNTgdvz4cWkmkE5kDATMioqKZkCFdiwg1eiAi4tLGqhQF24nMmBmZuYEigth1QkEbEBxTlySYPvJkwSJ00AnjYylgU6gxB8g/oFVEphkvgLF32KNMmCCewYUv4qhEyj47+HDhyeBzIMYOoEp8CxQw56wsLAncJ1//vz5/P79+2svX74EJc2V4BT58+fPd8CE/QKYHMGJOiIiAp6oWW7evDkNSF8DZYfIyEiU7AAQYACJ2vxVdJW4eQAAAABJRU5ErkJggg==) right top no-repeat;
}
.sf-button .btn-bg {
padding: 0px 14px;
color: #636363;
line-height: 28px;
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAYAAACgXdXMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAClJREFUeNpiPnny5EKGf//+/Wf6//8/A4QAcrGzKCZwGc9sa2urBBBgAIbDUoYVp9lmAAAAAElFTkSuQmCC) repeat-x top left;
}
.sf-button:hover .border-l,
.sf-button-selected .border-l {
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAR9JREFUeNpi/P//PwMyOHfunDqQSgNiexZkibNnzxYBqZa3HOs5v7PcYQBLnjlzhg1IbfzIdsTjA/t+ht9Mr8GKwZL//v3r+sB+0OMN+zqIEf8gFMvJkyd1gXTOa9YNDP//otrPAtSV/Jp9HfPff78Z0AEL0LUeXxivMfxD0wXTqfjj/2ugkf+wSrL9/YtpJEyS4S8WI5Ek/+GR/POPFjr//cenE6/kP9q4Fo/kr39/mdj+M/zFkGQCSj5i+ccPjLJ/GBgkuYOHQR1sNDpmAkb2LBmWwL///zKCIxwZM0VHR18G6p4uxeLLAA4tJMwEshiou1iMxXaHLGswA+t/YbhORuQUv2DBAnCifvxzI+enP3dQJUFg/vz5sOzgBBBgAPxX9j0YnH4JAAAAAElFTkSuQmCC) no-repeat top left;
}
.sf-button:hover .border-r,
.sf-button-selected .border-r {
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAcCAYAAACtQ6WLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAT5JREFUeNpiPHv27BkGBoaDQDzLyMjoJgMSYHrM3WX8hn1d0f///88DFRYhSzIuv2X5H8Rg/SfKIPDTkYH/l80OINffxMTkF9O/f/8ZQPgnwyuGl+wrGd6x7vf49+9fO9jYf3+Bkkj4NesmBqAV+SdPntQC6vzHgIz//gOawbqOGchOxtAJwp8Zr4F0e7D8/fuPAR38/P8eZIo0yz8skv8YvoIk+YE6/zNgAyD7sRqLkPzzjxY6/+HS+R+fTkZ8djLh08lCUCcuSWawJGbwMTGwg7zyBatX2Bj5QZKPsBrLzaICktzN8g/NWEYGZgYZjoC/wMiei5FMpFh8QPSU6Ojoy3Cd7EwiDBJsDgxiLNY7gLrKQGIsHAxSDHxAO2TZ/b8D+TVxcXF9MCtYtLiKLgDpfUDVsxITE1GyA0CAAQA2E/N8VuHyAAAAAABJRU5ErkJggg==) right top no-repeat;
}
.sf-button:hover .btn-bg,
.sf-button-selected .btn-bg {
color: #FFFFFF;
text-shadow:0 1px 1px #6b9311;
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAIAAAAvP0KbAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAEFJREFUeNpiPnv2LNMdvlymf///M/37B8R/QfQ/MP33L4j+B6Qh7L9//sHpf2h8MA1V+w/KRjYLaDaLCU8vQIABAFO3TxZriO4yAAAAAElFTkSuQmCC) repeat-x top left;
}

File diff suppressed because one or more lines are too long

View File

@ -1,50 +1,37 @@
{% extends '@WebProfiler/Profiler/base.html.twig' %}
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% block body %}
<div id="content">
{% include '@WebProfiler/Profiler/header.html.twig' only %}
{% set messages = {
'purge' : {
status: 'success',
title: 'The profiler database was purged successfully',
message: 'Now you need to browse some pages with the Symfony Profiler enabled to collect data.'
},
'no_token' : {
status: 'error',
title: (token|default('') == 'latest') ? 'There are no profiles' : 'Token not found',
message: (token|default('') == 'latest') ? 'No profiles found in the database.' : 'Token "' ~ token|default('') ~ '" was not found in the database.'
},
'upload_error' : {
status: 'error',
title: 'A problem occurred when uploading the data',
message: 'No file given or the file was not uploaded successfully.'
},
'already_exists' : {
status: 'error',
title: 'A problem occurred when uploading the data',
message: 'The token already exists in the database.'
}
} %}
<div id="main">
<div class="clear-fix">
<div id="collector-wrapper">
<div id="collector-content">
{% block panel %}
{% if about == 'purge' %}
<h2>The profiler database was purged successfully</h2>
<p>
<em>Now you need to browse some pages with the Symfony Profiler enabled to collect data.</em>
</p>
{% elseif about == 'upload_error' %}
<h2>A problem occurred when uploading the data</h2>
<p>
<em>No file given or the file was not uploaded successfully.</em>
</p>
{% elseif about == 'already_exists' %}
<h2>A problem occurred when uploading the data</h2>
<p>
<em>The token already exists in the database.</em>
</p>
{% elseif about == 'no_token' %}
{% if token == 'latest' %}
<h2>No profiles</h2>
<p>
<em>No profiles found in the database.</em>
</p>
{% else %}
<h2>Token not found</h2>
<p>
<em>Token "{{ token }}" was not found in the database.</em>
</p>
{% endif %}
{% endif %}
{% endblock %}
</div>
</div>
<div id="navigation">
{{ render(path('_profiler_search_bar')) }}
{% include '@WebProfiler/Profiler/admin.html.twig' with { 'token': '' } only %}
</div>
</div>
{% block summary %}
<div class="status status-{{ messages[about].status }}">
<div class="container">
<h2>{{ messages[about].status|title }}</h2>
</div>
</div>
{% endblock %}
{% block panel %}
<h2>{{ messages[about].title }}</h2>
<p>{{ messages[about].message }}</p>
{% endblock %}

View File

@ -1,131 +1,83 @@
{% extends '@WebProfiler/Profiler/base.html.twig' %}
{% block body %}
{{ include('@WebProfiler/Profiler/header.html.twig', with_context = false) }}
{{ render(path('_wdt', { 'token': token, 'position': 'normal' })) }}
<div id="summary">
{% block summary %}
{% if profile is defined %}
{% set status_code = ('request' in profile.collectors|keys) ? profile.getcollector('request').statuscode|default(0) : 0 %}
{% set css_class = status_code > 399 ? 'status-error' : status_code > 299 ? 'status-warning' : 'status-success' %}
<div id="content">
{% include '@WebProfiler/Profiler/header.html.twig' only %}
<div id="main">
<div class="clear-fix">
<div id="collector-wrapper">
{% if profile %}
<div id="resume">
<a id="resume-view-all" href="{{ path('_profiler_search', {limit: 10}) }}">View last 10</a>
<a id="resume-view-latest" href="{{ path('_profiler', {token: 'latest', 'panel': panel}) }}">View latest</a>
<strong>Profile for:</strong>
{{ profile.method|upper }}
<div class="status {{ css_class }}">
<div class="container">
<h2 class="break-long-words">
{% if profile.method|upper in ['GET', 'HEAD'] %}
<a href="{{ profile.url }}" id="resume-url">{{ profile.url }}</a>
<a href="{{ profile.url }}">{{ profile.url }}</a>
{% else %}
<span id="resume-url">{{ profile.url }}</span>
{{ profile.url }}
{% endif %}
<span class="date">
<em>by {{ profile.ip }}</em> at <em>{{ profile.time|date('r') }}</em>
</span>
</div>
{% endif %}
</h2>
<div id="collector-content">
{% include '@WebProfiler/Profiler/base_js.html.twig' %}
{% block panel '' %}
<dl class="metadata">
<dt>Method</dt>
<dd>{{ profile.method|upper }}</dd>
<dt>HTTP Status</dt>
<dd>{{ status_code }}</dd>
<dt>IP</dt>
<dd>{{ profile.ip }}</dd>
<dt>Profiled on</dt>
<dd>{{ profile.time|date('r') }}</dd>
<dt>Token</dt>
<dd>{{ profile.token }}</dd>
</dl>
</div>
</div>
<div id="navigation">
{% if templates is defined %}
<ul id="menu-profiler">
{% for name, template in templates %}
{% set menu %}{{ template.renderBlock('menu', { 'collector': profile.getcollector(name)}) }}{% endset %}
{% if menu != '' %}
<li class="{{ name }}{% if name == panel %} selected{% endif %}">
<a href="{{ path('_profiler', { 'token': token, 'panel': name }) }}">{{ menu|raw }}</a>
</li>
{% endif %}
{% endfor %}
<li class="minimize">
<a href="javascript:void(0);" title="Minimize toolbar" onclick="return toggleMenuPanels();">
<span class="label">
<span class="icon"><svg id="minimizePanelIcon" width="30" height="33" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 30 33" enable-background="new 0 0 30 33" xml:space="preserve"><path fill="#3F3F3F" d="M15 5C8.4 5 3 10.4 3 17c0 6.6 5.4 12 12 12s12-5.4 12-12C27 10.4 21.6 5 15 5z M19.1 21.5l-1.8 1.8L10.9 17 l6.3-6.3l1.8 1.8L14.6 17L19.1 21.5z"/></svg></span>
<strong>Minimize</strong>
</span>
</a>
</li>
</ul>
{% endif %}
{% endif %}
{% endblock %}
</div>
<div id="content" class="container">
<div id="main">
<div id="collector-wrapper">
<div id="collector-content">
{{ include('@WebProfiler/Profiler/base_js.html.twig') }}
{% block panel '' %}
</div>
</div>
<div id="sidebar">
<div id="sidebar-shortcuts">
<a class="btn btn-sm" href="{{ path('_profiler_search', { limit: 10 }) }}">Latest profiles</a>
<a class="sf-toggle btn btn-sm" data-toggle-selector="#sidebar-search" {% if tokens is defined or about is defined %}data-toggle-initial="display"{% endif %}>
{{ include('@WebProfiler/Icon/search.svg') }} Search
</a>
{{ render(path('_profiler_search_bar')) }}
{% include '@WebProfiler/Profiler/admin.html.twig' with { 'token': token } only %}
</div>
{% if templates is defined %}
<ul id="menu-profiler">
{% for name, template in templates %}
{% set menu %}{{ template.renderBlock('menu', { collector: profile.getcollector(name), profiler_markup_version: profiler_markup_version }) }}{% endset %}
{% if menu is not empty %}
<li class="{{ name }} {{ name == panel ? 'selected' : '' }}">
<a href="{{ path('_profiler', { token: token, panel: name }) }}">{{ menu|raw }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
<div class="module">
{{ include('@WebProfiler/Profiler/admin.html.twig', { token: token|default('') }, with_context = false) }}
</div>
</div>
</div>
</div>
<script>//<![CDATA[
function toggleMenuPanels(state, doSave) {
var menu = document.getElementById('navigation'), savedState = Sfjs.getPreference('menu/displayState'),
displayState, elem, className;
if (null === savedState) {
savedState = 'block';
}
displayState = state || ('block' === savedState ? 'none' : 'block');
if ('undefined' === typeof doSave) {
doSave = true;
}
document.getElementById('searchBar').style.display = displayState;
document.getElementById('adminBar').style.display = displayState;
if ('block' === displayState) {
Sfjs.removeClass(menu, 'collapsed-menu');
Sfjs.removeClass(menu.parentNode.parentNode, 'collapsed-menu-parents');
} else {
Sfjs.addClass(menu, 'collapsed-menu');
Sfjs.addClass(menu.parentNode.parentNode, 'collapsed-menu-parents');
}
if (doSave) {
Sfjs.setPreference('menu/displayState', displayState);
}
try {
canvasAutoUpdateOnThresholdChange(null);
} catch (err) {
}
return false;
}
window.setTimeout(function() {
if (null === document.getElementById('menu-profiler')) {
return;
}
var menuItems = document.getElementById('menu-profiler').getElementsByTagName('LI'),
elem, value, child, displayState = Sfjs.getPreference('menu/displayState');
if (displayState == 'none') {
toggleMenuPanels('none', false);
}
for (elem in menuItems) {
if (typeof(menuItems[elem].children) !== 'undefined' &&
menuItems[elem].children.length > 0) {
child = menuItems[elem].children[0];
if ('' === child.getAttribute('title') ||
null === child.getAttribute('title')) {
value = child.text.replace(/^\s+/g, '').split('\n')[0].replace(/\s+$/g, '');
child.setAttribute('title', value);
}
}
}
}, 25);
//]]></script>
{% endblock %}

View File

@ -1,43 +1,52 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
{% block summary %}
<div class="status">
<div class="container">
<h2>Profile Search</h2>
</div>
</div>
{% endblock %}
{% block panel %}
<h2>Search Results</h2>
<h2>{{ tokens ? tokens|length : 'No' }} results found</h2>
{% if tokens %}
<table>
<table id="search-results">
<thead>
<tr>
<th scope="col">Token</th>
<th scope="col" class="text-center">Status</th>
<th scope="col">IP</th>
<th scope="col">Method</th>
<th scope="col">URL</th>
<th scope="col">Time</th>
<th scope="col">Status</th>
<th scope="col">Token</th>
</tr>
</thead>
<tbody>
{% for elements in tokens %}
{% for result in tokens %}
{% set css_class = result.status_code|default(0) > 399 ? 'status-error' : result.status_code|default(0) > 299 ? 'status-warning' : 'status-success' %}
<tr>
<td><a href="{{ path('_profiler', { 'token': elements.token }) }}">{{ elements.token }}</a></td>
<td>{{ elements.ip }}</td>
<td>{{ elements.method }}</td>
<td>{{ elements.url }}</td>
<td>{{ elements.time|date('r') }}</td>
<td>
{% if elements.status_code is defined and elements.status_code %}
{{ elements.status_code }}
{% else %}
unknown
{% endif %}
<td class="text-center">
<span class="label {{ css_class }}">{{ result.status_code|default('n/a') }}</span>
</td>
<td class="nowrap">{{ result.ip }}</td>
<td>{{ result.method }}</td>
<td class="break-long-words">{{ result.url }}</td>
<td class="text-small">
<span class="nowrap">{{ result.time|date('d-M-Y') }}</span>
<span class="nowrap newline">{{ result.time|date('H:i:s') }}</span>
</td>
<td class="nowrap"><a href="{{ path('_profiler', { token: result.token }) }}">{{ result.token }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>
<em>The query returned no result.</em>
</p>
<div class="empty">
<p>The query returned no result.</p>
</div>
{% endif %}
{% endblock %}

View File

@ -1,46 +1,51 @@
<div class="search clearfix" id="searchBar">
<h3>
<img style="margin: 0 5px 0 0; vertical-align: middle;" width="16" height="16" alt="Search" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAC2ElEQVR42u3XvUtbYRQG8JcggSxSiqlQoXUQUfEDnDoIEkK30ulKh0REFEOkitaIaBUU4gchQ8BBGyKGIC79B7rVxaGlm+JooYtQCq2U0oq9OX0eOBeCRXrf69DFwI9z73nPeTlJbrxXIyL/1e0AfyWueTVAEgrwGt5qLGge675e1gPUQaqxsfEgmUyerq6uft3e3v61v78vjDxnnuusYz3WTI0bDXAnHA6/Gh0d/bS7u+vu7e3JdbjOOtazDzmjAg9QF41Gy+vr6+eVSkX8Yj372I9zA8EGiEQi6bW1tfNyuSyK7/II0YEmMBodzYuHfezXmkADNAwNDX3c2dkRKpVKl4hZCIO5SvNZ1LleD/uxzz0c2w/Q0tLyAheYWywWRT0H4wPrhNjf1taWYd56gOHh4XdbW1tC+Xz+CNH4pfVCuo/9AAsLC182NzeFVlZWUojGL60X0n3sB8BFdFEoFISWlpYeIhq/tF5I97EfIJfLufgohZqbm+8jGr+0Xkj3sR9geXn5x8bGhlBHR8czROOX1gvpPvYDzM3NnWSzWaFYLPYG0fil9UK6j/0As7OzWVxMQul0+ht6nuDY/AvrWO/16j7WA/BCerC4uHiJKNTX13eid7wQzs1VzHOddV4P+n9zHwj0l5BfQ35+fl4Ix248Hj8NhUIlLPXDXeQNI8+Z5zrrvJ6BgYEzrMVxHGgAfg3hmZmZD4jiwd3ue3d393F9ff0hnwcYec4812tlMplqb2/vMepigW/H09PTUXgPEsTU1FS1p6dHhwj4QDI5ORmBHFyAXEfXK+DW5icmJqpdXV21Q9g/ko2Pj1MTvIQDOAPReKD5Jq1zwAVR/CVVOzs7OUR/oAFSqZQtB1wQz9jYWLW9vf0I2z2yHgAXWRAOuCCekZGRamtr66HtALw9B+WAC+JJJBI/rQfA081NOOCCEJ6gP1sPMDg4eFNP4Uw9vv3X7HaAq/4AszA5PJFqlwgAAAAASUVORK5CYII=">
Search
</h3>
<div id="sidebar-search">
<form action="{{ path('_profiler_search') }}" method="get">
<label for="ip">IP</label>
<input type="text" name="ip" id="ip" value="{{ ip }}">
<div class="clear-fix"></div>
<label for="method">Method</label>
<select name="method" id="method">
<option value=""{{ '' == method ? ' selected="selected"' : '' }}>&nbsp;</option>
{% for m in ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'] %}
<option{{ m == method ? ' selected="selected"' : '' }}>{{ m }}</option>
{% endfor %}
</select>
<div class="clear-fix"></div>
<label for="url">URL</label>
<input type="text" name="url" id="url" value="{{ url }}">
<div class="clear-fix"></div>
<label for="token">Token</label>
<input type="text" name="token" id="token" value="{{ token }}">
<div class="clear-fix"></div>
<label for="start">From</label>
<input type="date" name="start" id="start" value="{{ start }}">
<div class="clear-fix"></div>
<label for="end">Until</label>
<input type="date" name="end" id="end" value="{{ end }}">
<div class="clear-fix"></div>
<label for="limit">Limit</label>
<select name="limit" id="limit">
{% for l in [10, 50, 100] %}
<option{{ l == limit ? ' selected="selected"' : '' }}>{{ l }}</option>
{% endfor %}
</select>
<div class="form-group">
<label for="ip">IP</label>
<input type="text" name="ip" id="ip" value="{{ ip }}">
</div>
<button type="submit" class="sf-button">
<span class="border-l">
<span class="border-r">
<span class="btn-bg">SEARCH</span>
</span>
</span>
</button>
<div class="clear-fix"></div>
<div class="form-group">
<label for="method">Method</label>
<select name="method" id="method">
<option value="">Any</option>
{% for m in ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'] %}
<option {{ m == method ? 'selected="selected"' }}>{{ m }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="url">URL</label>
<input type="text" name="url" id="url" value="{{ url }}">
</div>
<div class="form-group">
<label for="token">Token</label>
<input type="text" name="token" id="token" value="{{ token }}">
</div>
<div class="form-group">
<label for="start">From</label>
<input type="date" name="start" id="start" value="{{ start }}">
</div>
<div class="form-group">
<label for="end">Until</label>
<input type="date" name="end" id="end" value="{{ end }}">
</div>
<div class="form-group">
<label for="limit">Results</label>
<select name="limit" id="limit">
{% for l in [10, 50, 100] %}
<option {{ l == limit ? 'selected="selected"' }}>{{ l }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-sm">Search</button>
</div>
</form>
</div>

View File

@ -1,15 +1,15 @@
<table {% if class is defined %}class='{{ class }}'{% endif %} >
<table class="{{ class|default('') }}">
<thead>
<tr>
<th scope="col" style="width: 25%">Key</th>
<th scope="col" style="width: 75%">Value</th>
<th scope="col" class="key">{{ labels is defined ? labels[0] : 'Key' }}</th>
<th scope="col">{{ labels is defined ? labels[1] : 'Value' }}</th>
</tr>
</thead>
<tbody>
{% for key in data|keys|sort %}
<tr>
<th>{{ key }}</th>
<td><pre>{{ profiler_dump(data[key]) }}</pre></td>
<th scope="row">{{ key }}</th>
<td>{{ profiler_dump(data[key]) }}</td>
</tr>
{% endfor %}
</tbody>

View File

@ -1,5 +1,5 @@
<div id="sfwdt{{ token }}" class="sf-toolbar" style="display: none"></div>
{% include '@WebProfiler/Profiler/base_js.html.twig' %}
{{ include('@WebProfiler/Profiler/base_js.html.twig') }}
<script>/*<![CDATA[*/
(function () {
{% if 'top' == position %}

View File

@ -1,44 +1,78 @@
<h2>Routing for "{{ request.pathinfo }}"</h2>
<h2>Routing</h2>
<ul>
<li>
<strong>Route:&nbsp;</strong>
{% if request.route %}
{{ request.route }}
{% else %}
<em>No matching route</em>
{% endif %}
</li>
<li>
<strong>Route parameters:&nbsp;</strong>
{% if request.routeParams|length %}
{% include '@WebProfiler/Profiler/table.html.twig' with { 'data': request.routeParams, 'class': 'inline' } only %}
{% else %}
<em>No parameters</em>
{% endif %}
</li>
{% if router.redirect %}
<li>
<strong>Redirecting to:&nbsp;</strong> "{{ router.targetUrl }}" {% if router.targetRoute %}(route: "{{ router.targetRoute }}"){% endif %}
<li>
<div class="metrics">
<div class="metric">
<span class="value">{{ request.route ?: '(none)' }}</span>
<span class="label">Matched route</span>
</div>
{% if request.route %}
<div class="metric">
<span class="value">{{ traces|length }}</span>
<span class="label">Tested routes before match</span>
</div>
{% endif %}
<li>
<strong>Route matching logs</strong>
<table class="routing inline">
<tr>
<th>Route name</th>
<th>Pattern</th>
<th>Log</th>
</tr>
{% for trace in traces %}
<tr class="{{ 1 == trace.level ? 'almost' : 2 == trace.level ? 'matches' : '' }}">
<td>{{ trace.name }}</td>
<td>{{ trace.path }}</td>
<td>{{ trace.log }}</td>
</tr>
{% endfor %}
</table>
<em><small>Note: The above matching is based on the configuration for the current router which might differ from
the configuration used while routing this request.</small></em>
</li>
</ul>
</div>
{% if request.route %}
<h3>Route Parameters</h3>
{% if request.routeParams is empty %}
<div class="empty">
<p>No parameters.</p>
</div>
{% else %}
{{ include('@WebProfiler/Profiler/table.html.twig', { data: request.routeParams, labels: ['Name', 'Value'] }, with_context = false) }}
{% endif %}
{% endif %}
{% if router.redirect %}
<h3>Route Redirection</h3>
<p>This page redirects to:</p>
<div class="card" style="break-long-words">
{{ router.targetUrl }}
{% if router.targetRoute %}<span class="text-muted">(route: "{{ router.targetRoute }}")</span>{% endif %}
</div>
{% endif %}
<h3>Route Matching Logs</h3>
<div class="card">
<strong>Path to match:</strong> <code>{{ request.pathinfo }}</code>
</div>
<table id="router-logs">
<thead>
<tr>
<th>#</th>
<th>Route name</th>
<th>Path</th>
<th>Log</th>
</tr>
</thead>
<tbody>
{% for trace in traces %}
<tr class="{{ trace.level == 1 ? 'status-warning' : trace.level == 2 ? 'status-success' }}">
<td class="font-normal text-muted">{{ loop.index }}</td>
<td>{{ trace.name }}</td>
<td>{{ trace.path }}</td>
<td class="font-normal">
{% if trace.level == 1 %}
Path almost matches, but
<span class="newline">{{ trace.log }}</span>
{% elseif trace.level == 2 %}
{{ trace.log }}
{% else %}
Path does not match
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<p class="help">
Note: These matching logs are based on the current router configuration,
which might differ from the configuration used when profiling this request.
</p>

View File

@ -141,7 +141,8 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
$called = array();
foreach ($this->called as $eventName => $listeners) {
foreach ($listeners as $listener) {
$info = $this->getListenerInfo($listener->getWrappedListener(), $eventName);
$priority = $this->getListenerPriority($eventName, $listener);
$info = $this->getListenerInfo($listener->getWrappedListener(), $eventName, $priority);
$called[$eventName.'.'.$info['pretty']] = $info;
}
}
@ -155,7 +156,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
public function getNotCalledListeners()
{
try {
$allListeners = $this->getListeners();
$allListeners = $this->getListeners(null, true);
} catch (\Exception $e) {
if (null !== $this->logger) {
$this->logger->info('An exception was thrown while getting the uncalled listeners.', array('exception' => $e));
@ -166,26 +167,30 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
$notCalled = array();
foreach ($allListeners as $eventName => $listeners) {
foreach ($listeners as $listener) {
$called = false;
if (isset($this->called[$eventName])) {
foreach ($this->called[$eventName] as $l) {
if ($l->getWrappedListener() === $listener) {
$called = true;
foreach ($allListeners as $eventName => $priorities) {
foreach ($priorities as $priority => $listeners) {
foreach ($listeners as $listener) {
$called = false;
if (isset($this->called[$eventName])) {
foreach ($this->called[$eventName] as $l) {
if ($l->getWrappedListener() === $listener) {
$called = true;
break;
break;
}
}
}
}
if (!$called) {
$info = $this->getListenerInfo($listener, $eventName);
$notCalled[$eventName.'.'.$info['pretty']] = $info;
if (!$called) {
$info = $this->getListenerInfo($listener, $eventName, $priority);
$notCalled[$eventName.'.'.$info['pretty']] = $info;
}
}
}
}
uasort($notCalled, array($this, 'sortListenersByPriority'));
return $notCalled;
}
@ -281,10 +286,11 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
*
* @return array Information about the listener
*/
private function getListenerInfo($listener, $eventName)
private function getListenerInfo($listener, $eventName, $priority = null)
{
$info = array(
'event' => $eventName,
'priority' => $priority,
);
if ($listener instanceof \Closure) {
$info += array(
@ -332,4 +338,47 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
return $info;
}
private function getListenerPriority($eventName, $listenerConfig)
{
try {
$allListeners = $this->getListeners(null, true);
} catch (\Exception $e) {
if (null !== $this->logger) {
$this->logger->info('An exception was thrown while getting the listeners.', array('exception' => $e));
}
return;
}
$listenerWrapper = $listenerConfig->getWrappedListener();
foreach ($allListeners[$eventName] as $priority => $listeners) {
foreach ($listeners as $listener) {
if (is_array($listenerWrapper) && $listenerWrapper[0] === $listener[0]) {
return $priority;
}
}
}
}
private function sortListenersByPriority($a, $b)
{
if (is_int($a['priority']) && !is_int($b['priority'])) {
return 1;
}
if (!is_int($a['priority']) && is_int($b['priority'])) {
return -1;
}
if ($a['priority'] === $b['priority']) {
return 0;
}
if ($a['priority'] > $b['priority']) {
return -1;
}
return 1;
}
}

View File

@ -79,11 +79,11 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$tdispatcher->addListener('foo', $listener = function () {; });
$this->assertEquals(array(), $tdispatcher->getCalledListeners());
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getNotCalledListeners());
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure', 'priority' => 0)), $tdispatcher->getNotCalledListeners());
$tdispatcher->dispatch('foo');
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getCalledListeners());
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure', 'priority' => null)), $tdispatcher->getCalledListeners());
$this->assertEquals(array(), $tdispatcher->getNotCalledListeners());
}