10000 minor #12125 [VarDumper] Dynamic HTML dumper (nicolas-grekas) · wouterj/symfony@87d5856 · GitHub
[go: up one dir, main page]

Skip to content

Commit 87d5856

Browse files
committed
minor symfony#12125 [VarDumper] Dynamic HTML dumper (nicolas-grekas)
This PR was merged into the 2.6-dev branch. Discussion ---------- [VarDumper] Dynamic HTML dumper | Q | A | ------------- | --- | Bug fix? | yes | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | symfony#12109 | License | MIT | Doc PR | - This PR partially reverts symfony#12109 because it didn't take into account that many dumps can share a single style tag. More importantly, this PR enhance dump rendering with some cute JS navigation effects: - references highlighting on hovering - moving references toggling Here is a screenshot (note the yellow background and the fact that `#2` appears after the first `@2`): ![capture du 2014-10-04 09 45 44](https://cloud.githubusercontent.com/assets/243674/4514936/4431c67e-4b9b-11e4-9809-8d06836be824.png) Commits ------- b799844 [VarDumper] Dynamic HTML dumper
2 parents 3c81b52 + b799844 commit 87d5856

File tree

6 files changed

+116
-63
lines changed

6 files changed

+116
-63
lines changed

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@
286286
max-height: 480px;
287287
word-wrap: break-word;
288288
overflow: hidden;
289-
overflow-y: scroll;
289+
overflow-y: auto;
290290
}
291291

292292
table.sf-toolbar-ajax-requests {

src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,10 @@ public function testDump()
3535
$dump = $collector->getDumps('html');
3636
$this->assertTrue(isset($dump[0]['data']));
3737
$dump[0]['data'] = preg_replace('/^.*?<pre/', '<pre', $dump[0]['data']);
38-
preg_match('/sf-dump-(\\d{2,})/', $dump[0]['data'], $matches);
39-
$dumpId = $matches[1];
4038

4139
$xDump = array(
4240
array(
43-
'data' => "<pre id=sf-dump-{$dumpId}><span class=sf-dump-0><span class=sf-dump-num>123</span>\n</span></pre><script>Sfjs.dump.instrument()</script>\n",
41+
'data' => "<pre class=sf-dump><span class=sf-dump-num>123</span>\n</pre><script>Sfjs.dump.instrument()</script>\n",
4442
'name' => 'DumpDataCollectorTest.php',
4543
'file' => __FILE__,
4644
'line' => $line,

src/Symfony/Component/VarDumper/Dumper/CliDumper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ public function leaveObject(Cursor $cursor, $class, $hasChild, $cut)
224224
*/
225225
public function enterResource(Cursor $cursor, $res, $hasChild)
226226
{
227-
$this->enterHash($cursor, 'resource:'.$this->style('note', $res).' {', $hasChild);
227+
$this->enterHash($cursor, $this->style('note', ':'.$res).' {', $hasChild);
228228
}
229229

230230
/**

src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class HtmlDumper extends CliDumper
2424
public static $defaultOutputStream = 'php://output';
2525

2626
protected $dumpHeader;
27-
protected $dumpPrefix = '<pre id=%id%>';
27+
protected $dumpPrefix = '<pre class=sf-dump>';
2828
protected $dumpSuffix = '</pre><script>Sfjs.dump.instrument()</script>';
2929
protected $dumpId = 'sf-dump';
3030
protected $colors = true;
@@ -101,7 +101,7 @@ protected function getDumpHeader()
101101
$this->headerIsDumped = true;
102102

103103
if (null !== $this->dumpHeader) {
104-
return str_replace('%id%', $this->dumpId, $this->dumpHeader);
104+
return $this->dumpHeader;
105105
}
106106

107107
$line = <<<'EOHTML'
@@ -110,19 +110,81 @@ protected function getDumpHeader()
110110
Sfjs.dump = Sfjs.dump || {};
111111
Sfjs.dump.childElts = Sfjs.dump.childElts || document.getElementsByName('sf-dump-child');
112112
Sfjs.dump.childLen = Sfjs.dump.childLen || 0;
113+
Sfjs.dump.refElts = Sfjs.dump.refElts || document.getElementsByName('sf-dump-ref');
114+
Sfjs.dump.refLen = Sfjs.dump.refLen || 0;
115+
if (!Sfjs.dump.refStyle) {
116+
Sfjs.dump.refStyle = document.createElement('style');
117+
document.documentElement.firstChild.appendChild(Sfjs.dump.refStyle);
118+
}
113119
Sfjs.dump.instrument = Sfjs.dump.instrument || function () {
114-
var elt,
115-
i = this.childLen,
116-
aCompact = '▶</a><span class="sf-dump-compact">',
117-
aExpanded = '▼</a><span class="sf-dump-expanded">';
120+
var elt, i, ref;
118121
122+
i = this.childLen;
119123
this.childLen= this.childElts.length;
120124
121125
while (i < this.childLen) {
122126
elt = this.childElts[i];
123127
if ("" == elt.className) {
124128
elt.className = "sf-dump-child";
125-
elt.innerHTML = '<a class=sf-dump-ref onclick="Sfjs.dump.toggle(this)">'+('sf-dump-0' == elt.parentNode.className ? aExpanded : aCompact)+elt.innerHTML+'</span>';
129+
elt.innerHTML = '<a class=sf-dump-ref onclick="Sfjs.dump.toggle(this)"><span>▼</span></a><span class="sf-dump-expanded">'+elt.innerHTML+'</span>';
130+
if ('sf-dump-expanded' == elt.parentNode.className) {
131+
if (elt.children[1].firstChild.nextSibling.id) {
132+
elt.firstChild.appendChild(elt.children[1].firstChild);
133+
elt.firstChild.appendChild(elt.children[1].firstChild);
134+
}
135+
Sfjs.dump.toggle(elt.firstChild);
136+
}
137+
}
138+
++i;
139+
}
140+
141+
i = this.refLen;
142+
this.refLen= this.refElts.length;
143+
144+
function instrumentRef(elt) {
145+
var ref = elt.id;
146+
147+
if (elt.href) {
148+
ref = elt.getAttribute('href').substr(1);
149+
if ('@' == elt.innerHTML.charAt(0)) {
150+
elt.onclick = function() {
151+
var r = document.getElementById(ref).parentNode.parentNode,
152+
f = r && r.parentNode,
153+
t = elt.parentNode,
154+
c = elt.cloneNode(true);
155+
if (r && r.className == "sf-dump-child") {
156+
f.insertBefore(c, r);
157+
try {
158+
t.replaceChild(r, elt);
159+
f.replaceChild(elt, c);
160+
Sfjs.dump.refStyle.innerHTML = '';
161+
r = r.firstChild;
162+
c = r.nextSibling;
163+
if ('sf-dump-compact' == c.className) {
164+
Sfjs.dump.toggle(r);
165+
}
166+
167+
return false;
168+
} catch (e) {
169+
f.removeChild(c);
170+
}
171+
}
172+
};
173+
}
174+
}
175+
elt.className += ' '+ref;
176+
elt.onmouseover = function() {
177+
Sfjs.dump.refStyle.innerHTML = 'pre.sf-dump .'+ref+'{background-color: yellow; border-radius: 2px}';
178+
};
179+
elt.onmouseout = function() {
180+
Sfjs.dump.refStyle.innerHTML = '';
181+
};
182+
}
183+
184+
while (i < this.refLen) {
185+
elt = this.refElts[i];
186+
if ("sf-dump-ref" == elt.className) {
187+
instrumentRef(elt);
126188
}
127189
++i;
128190
}
@@ -131,51 +193,47 @@ protected function getDumpHeader()
131193
var s = a.nextElementSibling;
132194
133195
if ('sf-dump-compact' == s.className) {
134-
a.innerHTML = '▼';
196+
a.firstChild.innerHTML = '▼';
135197
s.className = 'sf-dump-expanded';
136198
} else {
137-
a.innerHTML = '▶';
199+
a.firstChild.innerHTML = '▶';
138200
s.className = 'sf-dump-compact';
139201
}
140202
};
141203
</script>
142204
<style>
143-
#%id% {
205+
pre.sf-dump {
144206
display: block;
145207
background-color: #300a24;
146208
white-space: pre;
147209
line-height: 1.2em;
148210
color: #eee8d5;
149211
font: 12px monospace, sans-serif;
150212
padding: 5px;
213+
border-radius: 5px;
151214
}
152-
#%id% span {
215+
pre.sf-dump span {
153216
display: inline;
154217
}
155-
#%id% .sf-dump-compact {
218+
pre.sf-dump .sf-dump-compact {
156219
display: none;
157220
}
158-
#%id% abbr {
221+
pre.sf-dump abbr {
159222
text-decoration: none;
160223
border: none;
161224
cursor: help;
162225
}
163-
#%id% a {
226+
pre.sf-dump a {
164227
text-decoration: none;
165228
cursor: pointer;
166229
}
167-
#%id% a:hover {
168-
text-decoration: underline;
169-
}
170230
EOHTML;
171231

172232
foreach ($this->styles as $class => $style) {
173-
$line .= "#%id% .sf-dump-$class {{$style}}";
233+
$line .= "pre.sf-dump .sf-dump-$class {{$style}}";
174234
}
175235

176-
$this->dumpHeader = preg_replace('/\s+/', ' ', $line).'</style>'.$this->dumpHeader;
177-
178-
return str_replace('%id%', $this->dumpId, $this->dumpHeader);
236+
return $this->dumpHeader = preg_replace('/\s+/', ' ', $line).'</style>'.$this->dumpHeader;
179237
}
180238

181239
/**
@@ -214,9 +272,9 @@ protected function style($style, $val)
214272
if ('ref' === $style) {
215273
$ref = substr($val, 1);
216274
if ('#' === $val[0]) {
217-
return "<span class=sf-dump-ref id=\"{$this->dumpId}-ref$ref\">$val</span>";
275+
return "<span class=sf-dump-ref name=sf-dump-ref id=\"{$this->dumpId}-ref$ref\">$val</span>";
218276
} else {
219-
return "<a class=sf-dump-ref href=\"#{$this->dumpId}-ref$ref\">$val</a>";
277+
return "<a class=sf-dump-ref name=sf-dump-ref href=\"#{$this->dumpId}-ref$ref\">$val</a>";
220278
}
221279
}
222280

@@ -231,7 +289,9 @@ protected function style($style, $val)
231289
}
232290
} elseif ('note' === $style) {
233291
if (false !== $c = strrpos($val, '\\')) {
234-
$val = sprintf('<abbr title="%s" class=sf-dump-%s>%s</abbr>', $val, $style, substr($val, $c+1));
292+
return sprintf('<abbr title="%s" class=sf-dump-%s>%s</abbr>', $val, $style, substr($val, $c+1));
293+
} elseif (':' === $val[0]) {
294+
return sprintf('<abbr title="Resource of type `%s`" class=sf-dump-%s>%s</abbr>', substr($val, 1), $style, $val);
235295
}
236296
}
237297

@@ -243,20 +303,15 @@ protected function style($style, $val)
243303
*/
244304
protected function dumpLine($depth)
245305
{
246-
switch ($this->lastDepth - $depth) {
247-
case +1: $this->line = '</span>'.$this->line; break;
248-
case -1: $this->line = "<span class=sf-dump-$depth>$this->line"; break;
249-
}
250-
251306
if (-1 === $this->lastDepth) {
252-
$this->line = str_replace('%id%', $this->dumpId, $this->dumpPrefix).$this->line;
307+
$this->line = $this->dumpPrefix.$this->line;
253308
}
254309
if (!$this->headerIsDumped) {
255310
$this->line = $this->getDumpHeader().$this->line;
256311
}
257312

258313
if (-1 === $depth) {
259-
$this->line .= str_replace('%id%', $this->dumpId, $this->dumpSuffix);
314+
$this->line .= $this->dumpSuffix;
260315
parent::dumpLine(0);
261316
}
262317
$this->lastDepth = $depth;

src/Symfony/Component/VarDumper/Tests/CliDumperTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function testGet()
5757
"str" => "déjà"
5858
7 => b"é"
5959
"[]" => []
60-
"res" => resource:stream {
60+
"res" => :stream {
6161
wrapper_type: "plainfile"
6262
stream_type: "STDIO"
6363
mode: "r"
@@ -68,7 +68,7 @@ public function testGet()
6868
eof: false
6969
options: []
7070
}
71-
8 => resource:Unknown {}
71+
8 => :Unknown {}
7272
"obj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo { #2
7373
foo: "foo"
7474
"bar": "bar"

src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ public function testGet()
4444
$out = preg_replace('/[ \t]+$/m', '', $out);
4545
$var['file'] = htmlspecialchars($var['file'], ENT_QUOTES, 'UTF-8');
4646
$intMax = PHP_INT_MAX;
47-
preg_match('/sf-dump-(\\d{2,})/', $out, $matches);
48-
$dumpId = $matches[1];
47+
preg_match('/sf-dump-\d+/', $out, $dumpId);
48+
$dumpId = $dumpId[0];
4949

5050
$this->assertSame(
5151
<<<EOTXT
52-
<foo></foo><bar><span class=sf-dump-0><span class=sf-dump-note>array:25</span> [<span name=sf-dump-child>
53-
<span class=sf-dump-1>"<span class=sf-dump-meta>number</span>" => <span class=sf-dump-num>1</span>
54-
<span class=sf-dump-meta>0</span> => <span class=sf-dump-const>null</span> <span class=sf-dump-ref id="sf-dump-{$dumpId}-ref1">#1</span>
52+
<foo></foo><bar><span class=sf-dump-note>array:25</span> [<span name=sf-dump-child>
53+
"<span class=sf-dump-meta>number</span>" => <span class=sf-dump-num>1</span>
54+
<span class=sf-dump-meta>0</span> => <span class=sf-dump-const>null</span> <span class=sf-dump-ref name=sf-dump-ref id="{$dumpId}-ref1">#1</span>
5555
"<span class=sf-dump-meta>const</span>" => <span class=sf-dump-num>1.1</span>
5656
<span class=sf-dump-meta>1</span> => <span class=sf-dump-const>true</span>
5757
<span class=sf-dump-meta>2</span> => <span class=sf-dump-const>false</span>
@@ -62,8 +62,8 @@ public function testGet()
6262
"<span class=sf-dump-meta>str</span>" => "<span class=sf-dump-str>d&#233;j&#224;</span>"
6363
<span class=sf-dump-meta>7</span> => b"<span class=sf-dump-str>&#233;</span>"
6464
"<span class=sf-dump-meta>[]</span>" => []
65-
"<span class=sf-dump-meta>res</span>" => resource:<span class=sf-dump-note>stream</span> {<span name=sf-dump-child>
66-
<span class=sf-dump-2><span class=sf-dump-meta>wrapper_type</span>: "<span class=sf-dump-str>plainfile</span>"
65+
"<span class=sf-dump-meta>res</span>" => <abbr title="Resource of type `stream`" class=sf-dump-note>:stream</abbr> {<span name=sf-dump-child>
66+
<span class=sf-dump-meta>wrapper_type</span>: "<span class=sf-dump-str>plainfile</span>"
6767
<span class=sf-dump-meta>stream_type</span>: "<span class=sf-dump-str>STDIO</span>"
6868
<span class=sf-dump-meta>mode</span>: "<span class=sf-dump-str>r</span>"
6969
<span class=sf-dump-meta>unread_bytes</span>: <span class=sf-dump-num>0</span>
@@ -72,14 +72,14 @@ public function testGet()
7272
<span class=sf-dump-meta>blocked</span>: <span class=sf-dump-const>true</span>
7373
<span class=sf-dump-meta>eof</span>: <span class=sf-dump-const>false</span>
7474
<span class=sf-dump-meta>options</span>: []
75-
</span></span>}
76-
<span class=sf-dump-meta>8</span> => resource:<span class=sf-dump-note>Unknown</span> {}
77-
"<span class=sf-dump-meta>obj</span>" => <span class=sf-dump-note><abbr title="Symfony\Component\VarDumper\Tests\Fixture\DumbFoo" class=sf-dump-note>DumbFoo</abbr></span> {<span name=sf-dump-child> <span class=sf-dump-ref id="sf-dump-{$dumpId}-ref2">#2</span>
78-
<span class=sf-dump-2><span class=sf-dump-public>foo</span>: "<span class=sf-dump-str>foo</span>"
75+
</span>}
76+
<span class=sf-dump-meta>8</span> => <abbr title="Resource of type `Unknown`" class=sf-dump-note>:Unknown</abbr> {}
77+
"<span class=sf-dump-meta>obj</span>" => <abbr title="Symfony\Component\VarDumper\Tests\Fixture\DumbFoo" class=sf-dump-note>DumbFoo</abbr> {<span name=sf-dump-child> <span class=sf-dump-ref name=sf-dump-ref id="{$dumpId}-ref2">#2</span>
78+
<span class=sf-dump-public>foo</span>: "<span class=sf-dump-str>foo</span>"
7979
"<span class=sf-dump-public>bar</span>": "<span class=sf-dump-str>bar</span>"
80-
</span></span>}
80+
</span>}
8181
"<span class=sf-dump-meta>closure</span>" => <span class=sf-dump-note>Closure</span> {<span name=sf-dump-child>
82-
<span class=sf-dump-2><span class=sf-dump-meta>reflection</span>: """
82+
<span class=sf-dump-meta>reflection</span>: """
8383
<span class=sf-dump-str>Closure [ &lt;user&gt; {$closureLabel} Symfony\Component\VarDumper\Tests\Fixture\{closure} ] {</span>
8484
<span class=sf-dump-str> @@ {$var['file']} {$var['line']} - {$var['line']}</span>
8585
@@ -89,22 +89,22 @@ public function testGet()
8989
<span class=sf-dump-str> }</span>
9090
<span class=sf-dump-str>}</span>
9191
"""
92-
</span></span>}
92+
</span>}
9393
"<span class=sf-dump-meta>line</span>" => <span class=sf-dump-num>{$var['line']}</span>
9494
"<span class=sf-dump-meta>nobj</span>" => <span class=sf-dump-note>array:1</span> [<span name=sf-dump-child>
95-
<span class=sf-dump-2><span class=sf-dump-meta>0</span> => {} <span class=sf-dump-ref id="sf-dump-{$dumpId}-ref3">#3</span>
96-
</span></span>]
97-
"<span class=sf-dump-meta>recurs</span>" => <span class=sf-dump-note>array:1</span> [<span name=sf-dump-child> <span class=sf-dump-ref id="sf-dump-{$dumpId}-ref4">#4</span>
98-
<span class=sf-dump-2><span class=sf-dump-meta>0</span> => <a class=sf-dump-ref href="#sf-dump-{$dumpId}-ref4">&4</a> <span class=sf-dump-note>array:1</span> [<a class=sf-dump-ref href="#sf-dump-{$dumpId}-ref4">@4</a>]
99-
</span></span>]
100-
<span class=sf-dump-meta>9</span> => <a class=sf-dump-ref href="#sf-dump-{$dumpId}-ref1">&1</a> <span class=sf-dump-const>null</span>
101-
"<span class=sf-dump-meta>sobj</span>" => <span class=sf-dump-note><abbr title="Symfony\Component\VarDumper\Tests\Fixture\DumbFoo" class=sf-dump-note>DumbFoo</abbr></span> {<a class=sf-dump-ref href="#sf-dump-{$dumpId}-ref2">@2</a>}
102-
"<span class=sf-dump-meta>snobj</span>" => <a class=sf-dump-ref href="#sf-dump-{$dumpId}-ref3">&3</a> {<a class=sf-dump-ref href="#sf-dump-{$dumpId}-ref3">@3</a>}
103-
"<span class=sf-dump-meta>snobj2</span>" => {<a class=sf-dump-ref href="#sf-dump-{$dumpId}-ref3">@3</a>}
95+
<span class=sf-dump-meta>0</span> => {} <span class=sf-dump-ref name=sf-dump-ref id="{$dumpId}-ref3">#3</span>
96+
</span>]
97+
"<span class=sf-dump-meta>recurs</span>" => <span class=sf-dump-note>array:1</span> [<span name=sf-dump-child> <span class=sf-dump-ref name=sf-dump-ref id="{$dumpId}-ref4">#4</span>
98+
<span class=sf-dump-meta>0</span> => <a class=sf-dump-ref name=sf-dump-ref href="#{$dumpId}-ref4">&4</a> <span class=sf-dump-note>array:1</span> [<a class=sf-dump-ref name=sf-dump-ref href="#{$dumpId}-ref4">@4</a>]
99+
</span>]
100+
<span class=sf-dump-meta>9</span> => <a class=sf-dump-ref name=sf-dump-ref href="#{$dumpId}-ref1">&1</a> <span class=sf-dump-const>null</span>
101+
"<span class=sf-dump-meta>sobj</span>" => <abbr title="Symfony\Component\VarDumper\Tests\Fixture\DumbFoo" class=sf-dump-note>DumbFoo</abbr> {<a class=sf-dump-ref name=sf-dump-ref href="#{$dumpId}-ref2">@2</a>}
102+
"<span class=sf-dump-meta>snobj</span>" => <a class=sf-dump-ref name=sf-dump-ref href="#{$dumpId}-ref3">&3</a> {<a class=sf-dump-ref name=sf-dump-ref href="#{$dumpId}-ref3">@3</a>}
103+
"<span class=sf-dump-meta>snobj2</span>" => {<a class=sf-dump-ref name=sf-dump-ref href="#{$dumpId}-ref3">@3</a>}
104104
"<span class=sf-dump-meta>file</span>" => "<span class=sf-dump-str>{$var['file']}</span>"
105105
b"<span class=sf-dump-meta>bin-key-&#233;</span>" => ""
106-
</span></span>]
107-
</span></bar>
106+
</span>]
107+
</bar>
108108
109109
EOTXT
110110
,

0 commit comments

Comments
 (0)
0