Skip to content

Commit ca92cd0

Browse files
committed
Added twig files into the FlattenException and improved an exception page
1 parent bb9c0a7 commit ca92cd0

File tree

9 files changed

+192
-14
lines changed

9 files changed

+192
-14
lines changed

src/Symfony/Bridge/Twig/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
2.7.0
5+
-----
6+
7+
* added TwigFlattener which adds twig files into the FlattenException
8+
49
2.5.0
510
-----
611

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Twig\Debug;
13+
14+
use Symfony\Component\Debug\Exception\FlattenException;
15+
use Symfony\Component\Debug\ExceptionFlattenerInterface;
16+
17+
/**
18+
* TwigFlattener adds twig files into FlattenException
19+
*
20+
* @author Martin Hasoň <martin.hason@gmail.com>
21+
*/
22+
class TwigFlattener implements ExceptionFlattenerInterface
23+
{
24+
private $loader;
25+
26+
public function __construct(\Twig_LoaderInterface $loader)
27+
{
28+
$this->loader = $loader;
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function flatten(\Exception $exception, FlattenException $flattenException, $options = array())
35+
{
36+
$trace = $flattenException->getTrace();
37+
$origTrace = $exception->getTrace();
38+
39+
switch (count($trace) - count($origTrace)) {
40+
case 0:
41+
$from = 0;
42+
break;
43+
case 1:
44+
$from = 1;
45+
break;
46+
default:
47+
throw new \InvalidArgumentException();
48+
}
49+
50+
foreach ($origTrace as $key => $entry) {
51+
if (!isset($origTrace[$key - 1]) || !isset($entry['class']) || 'Twig_Template' === $entry['class'] || !is_subclass_of($entry['class'], 'Twig_Template')) {
52+
continue;
53+
}
54+
55+
$template = unserialize(sprintf('O:%d:"%s":0:{}', strlen($entry['class']), $entry['class']));
56+
57+
$data = array('name' => $template->getTemplateName());
58+
$path = $this->loader->getCacheKey($data['name']);
59+
if (is_file($path)) {
60+
$data['path'] = $path;
61+
}
62+
63+
if (isset($origTrace[$key - 1]['line'])) {
64+
$line = $origTrace[$key - 1]['line'];
65+
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
66+
if ($codeLine <= $line) {
67+
$data['line'] = $templateLine;
68+
break;
69+
}
70+
}
71+
}
72+
73+
$trace[$from + $key - 1]['related_files'][] = $data;
74+
$trace[$from + $key - 1]['tags'][] = 'twig';
75+
}
76+
77+
if ($from == 1 && $exception instanceof \Twig_Error) {
78+
$data = array(
79+
'path' => $exception->getTemplateFile(),
80+
'line' => $exception->getTemplateLine(),
81+
);
82+
83+
$trace[0]['related_files'][] = $data;
84+
$trace[0]['tags'][] = 'twig';
85+
}
86+
87+
$flattenException->setRawTrace($trace);
88+
89+
return $flattenException;
90+
}
91+
}

src/Symfony/Bridge/Twig/composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"symfony/security": "~2.4",
3232
"symfony/stopwatch": "~2.2",
3333
"symfony/console": "~2.2",
34+
"symfony/debug": "~2.6",
3435
"symfony/var-dumper": "~2.6",
3536
"symfony/expression-language": "~2.4"
3637
},
@@ -44,6 +45,7 @@
4445
"symfony/yaml": "For using the YamlExtension",
4546
"symfony/security": "For using the SecurityExtension",
4647
"symfony/stopwatch": "For using the StopwatchExtension",
48+
"symfony/debug": "For using the TwigFlattener",
4749
"symfony/var-dumper": "For using the DumpExtension",
4850
"symfony/expression-language": "For using the ExpressionExtension"
4951
},

src/Symfony/Bundle/FrameworkBundle/Resources/public/css/exception.css

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
.sf-reset .traces {
22
padding-bottom: 14px;
33
}
4-
.sf-reset .traces li {
4+
.sf-reset .traces > li {
5+
position: relative;
56
font-size: 12px;
67
color: #868686;
7-
padding: 5px 4px;
8+
padding: 5px 4px 5px 24px;
89
list-style-type: decimal;
910
margin-left: 20px;
1011
white-space: break-word;
1112
}
13+
.sf-reset .traces > li.even {
14+
background-color: #F8F8F8;
15+
}
16+
.sf-reset .traces li .toggle-icon {
17+
margin-left: -20px;
18+
}
1219
.sf-reset #logs .traces li.error {
1320
font-style: normal;
1421
color: #AA3333;
@@ -111,3 +118,17 @@
111118
font-size: 12px;
112119
font-family: monospace;
113120
}
121+
.sf-reset .traces .tags {
122+
position: absolute;
123+
right: 4px;
124+
top: 5px;
125+
}
126+
.sf-reset .traces .tags .tag {
127+
display: inline-block;
128+
background-color: #aacd4e;
129+
border-radius: 6px;
130+
padding: 4px;
131+
color: #fff;
132+
margin-right: 2px;
133+
font-size: 11px;
134+
}

src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,10 @@
134134
<argument type="service" id="twig" />
135135
<argument>%kernel.debug%</argument>
136136
</service>
137+
138+
<service id="twig.exception_flattener" class="Symfony\Bridge\Twig\Debug\TwigFlattener" public="false">
139+
<tag name="exception.flattener" />
140+
<argument type="service" id="twig.loader" />
141+
</service>
137142
</services>
138143
</container>
Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
<div>
2+
{% spaceless %}
3+
<span class="toggle-icon">
4+
<a href="#" onclick="toggle('data-{{ prefix ~ '-' ~ i }}'); switchIcons('icon-{{ prefix ~ '-' ~ i }}-open', 'icon-{{ prefix ~ '-' ~ i }}-close'); return false;">
5+
<img class="toggle" id="icon-{{ prefix ~ '-' ~ i }}-close" alt="-" src="data:image/gif;base64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1+mC24IvK6ePx+Wa44dXs92+942e54o3L6W2844/M6dnu+P/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD/ER/wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO+hE0EoNAstEYGxG9heIhCADs=" style="display: {{ 0 == i ? 'inline' : 'none' }}" />
6+
<img class="toggle" id="icon-{{ prefix ~ '-' ~ i }}-open" alt="+" src="data:image/gif;base64,R0lGODlhEgASAMQTANft99/v+Ga44bHb8ITG52S44dXs9+z1+uPx+YvK6WC24G+944/M6W28443L6dnu+Ge54v/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5/vFID/DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7" style="display: {{ 0 == i ? 'none' : 'inline' }}" />
7+
</a>
8+
</span>
9+
{% endspaceless %}
10+
111
{% if trace.function %}
212
at
313
<strong>
@@ -10,13 +20,31 @@
1020
{% if trace.file is defined and trace.file and trace.line is defined and trace.line %}
1121
{{ trace.function ? '<br />' : '' }}
1222
in {{ trace.file|format_file(trace.line) }}&nbsp;
13-
{% spaceless %}
14-
<a href="#" onclick="toggle('trace-{{ prefix ~ '-' ~ i }}'); switchIcons('icon-{{ prefix ~ '-' ~ i }}-open', 'icon-{{ prefix ~ '-' ~ i }}-close'); return false;">
15-
<img class="toggle" id="icon-{{ prefix ~ '-' ~ i }}-close" alt="-" src="data:image/gif;base64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1+mC24IvK6ePx+Wa44dXs92+942e54o3L6W2844/M6dnu+P/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD/ER/wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO+hE0EoNAstEYGxG9heIhCADs=" style="display: {{ 0 == i ? 'inline' : 'none' }}" />
16-
<img class="toggle" id="icon-{{ prefix ~ '-' ~ i }}-open" alt="+" src="data:image/gif;base64,R0lGODlhEgASAMQTANft99/v+Ga44bHb8ITG52S44dXs9+z1+uPx+YvK6WC24G+944/M6W28443L6dnu+Ge54v/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABMALAAAAAASABIAQAVS4DQBTiOd6LkwgJgeUSzHSDoNaZ4PU6FLgYBA5/vFID/DbylRGiNIZu74I0h1hNsVxbNuUV4d9SsZM2EzWe1qThVzwWFOAFCQFa1RQq6DJB4iIQA7" style="display: {{ 0 == i ? 'none' : 'inline' }}" />
17-
</a>
18-
{% endspaceless %}
19-
<div id="trace-{{ prefix ~ '-' ~ i }}" style="display: {{ 0 == i ? 'block' : 'none' }}" class="trace">
20-
{{ trace.file|file_excerpt(trace.line) }}
21-
</div>
2223
{% endif %}
24+
25+
{% if trace.tags is defined and trace.tags is not empty %}
26+
<span class="tags">
27+
{% for tag in trace.tags %}
28+
<span class="tag">{{ tag }}</span>
29+
{% endfor %}
30+
</span>
31+
{% endif %}
32+
</div>
33+
34+
<div id="data-{{ prefix ~ '-' ~ i }}" style="display: {{ 0 == i ? 'block' : 'none' }}">
35+
{% if trace.file is defined and trace.file and trace.line is defined and trace.line %}
36+
<em>{{ trace.file|format_file(trace.line) }}</em>
37+
<div class="trace">
38+
{{ trace.file|file_excerpt(trace.line) }}
39+
</div>
40+
{% endif %}
41+
42+
{% if trace.related_files is defined and trace.related_files is not empty %}
43+
{% for file in trace.related_files if file.path is defined %}
44+
<em>{{ file.path|format_file(file.line|default(1), file.name|default(none)) }}</em>
45+
<div class="trace">
46+
{{ file.path|file_excerpt(file.line|default(1)) }}
47+
</div>
48+
{% endfor %}
49+
{% endif %}
50+
</div>

src/Symfony/Bundle/TwigBundle/Resources/views/Exception/traces.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<a id="traces-link-{{ position }}"></a>
1818
<ol class="traces list-exception" id="traces-{{ position }}" style="display: {{ 0 == count ? 'block' : 'none' }}">
1919
{% for i, trace in exception.trace %}
20-
<li>
20+
<li class="{{ cycle(['odd', 'even'], i) }}">
2121
{% include 'TwigBundle:Exception:trace.html.twig' with { 'prefix': position, 'i': i, 'trace': trace } only %}
2222
</li>
2323
{% endfor %}

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.css.twig

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
.sf-reset .traces {
22
padding-bottom: 14px;
33
}
4-
.sf-reset .traces li {
4+
.sf-reset .traces > li {
5+
position: relative;
56
font-size: 12px;
67
color: #868686;
7-
padding: 5px 4px;
8+
padding: 5px 4px 5px 24px;
89
list-style-type: decimal;
910
margin-left: 20px;
1011
white-space: break-word;
1112
}
13+
.sf-reset .traces > li.even {
14+
background-color: #F8F8F8;
15+
}
16+
.sf-reset .traces li .toggle-icon {
17+
margin-left: -20px;
18+
}
1219
.sf-reset #logs .traces li.error {
1320
font-style: normal;
1421
color: #AA3333;
@@ -102,3 +109,17 @@
102109
color: #000;
103110
font-size: 12px;
104111
}
112+
.sf-reset .traces .tags {
113+
position: absolute;
114+
right: 4px;
115+
top: 5px;
116+
}
117+
.sf-reset .traces .tags .tag {
118+
display: inline-block;
119+
background-color: #aacd4e;
120+
border-radius: 6px;
121+
padding: 4px;
122+
color: #fff;
123+
margin-right: 2px;
124+
font-size: 11px;
125+
}

src/Symfony/Component/Debug/Exception/FlattenException.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ public function setTrace($trace, $file, $line)
210210
}
211211
}
212212

213+
public function setRawTrace($trace)
214+
{
215+
$this->trace = $trace;
216+
}
217+
213218
private function flattenArgs($args, $level = 0)
214219
{
215220
$result = array();

0 commit comments

Comments
 (0)