Skip to content

Commit 2e167ba

Browse files
[TwigBridge] add Twig dump() function + tests and fixes
1 parent 0f8d30f commit 2e167ba

File tree

19 files changed

+379
-143
lines changed

19 files changed

+379
-143
lines changed

composer.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,7 @@
8585
"src/Symfony/Component/HttpFoundation/Resources/stubs",
8686
"src/Symfony/Component/Intl/Resources/stubs"
8787
],
88-
"files": [
89-
"src/Symfony/Component/Intl/Resources/stubs/functions.php",
90-
"src/Symfony/Component/VarDumper/Resources/functions/dump.php"
91-
]
88+
"files": [ "src/Symfony/Component/Intl/Resources/stubs/functions.php" ]
9289
},
9390
"minimum-stability": "dev",
9491
"extra": {

src/Symfony/Bridge/Twig/Extension/DumpExtension.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Bridge\Twig\Extension;
1313

1414
use Symfony\Bridge\Twig\TokenParser\DumpTokenParser;
15+
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
16+
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
1517

1618
/**
1719
* Provides integration of the dump() function with Twig.
@@ -20,6 +22,18 @@
2022
*/
2123
class DumpExtension extends \Twig_Extension
2224
{
25+
public function __construct(ClonerInterface $cloner = null)
26+
{
27+
$this->cloner = $cloner;
28+
}
29+
30+
public function getFunctions()
31+
{
32+
return array(
33+
new \Twig_SimpleFunction('dump', array($this, 'dump'), array('is_safe' => array('html'), 'needs_context' => true, 'needs_environment' => true)),
34+
);
35+
}
36+
2337
public function getTokenParsers()
2438
{
2539
return array(new DumpTokenParser());
@@ -29,4 +43,38 @@ public function getName()
2943
{
3044
return 'dump';
3145
}
46+
47+
public function dump(\Twig_Environment $env, $context)
48+
{
49+
if (!$env->isDebug() || !$this->cloner) {
50+
return;
51+
}
52+
53+
if (2 === func_num_args()) {
54+
$vars = array();
55+
foreach ($context as $key => $value) {
56+
if (!$value instanceof \Twig_Template) {
57+
$vars[$key] = $value;
58+
}
59+
}
60+
61+
$vars = array($vars);
62+
} else {
63+
$vars = func_get_args();
64+
unset($vars[0], $vars[1]);
65+
}
66+
67+
$html = '';
68+
$dumper = new HtmlDumper(function ($line, $depth) use (&$html) {
69+
if (-1 !== $depth) {
70+
$html .= str_repeat(' ', $depth).$line."\n";
71+
}
72+
});
73+
74+
foreach ($vars as $value) {
75+
$dumper->dump($this->cloner->cloneVar($value));
76+
}
77+
78+
return $html;
79+
}
3280
}

src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,22 @@
1313

1414
use Symfony\Bridge\Twig\Extension\DumpExtension;
1515
use Symfony\Component\VarDumper\VarDumper;
16+
use Symfony\Component\VarDumper\Cloner\PhpCloner;
1617

1718
class DumpExtensionTest extends \PHPUnit_Framework_TestCase
1819
{
1920
/**
20-
* @dataProvider getDumpParams
21+
* @dataProvider getDumpTags
2122
*/
22-
public function testDebugDump($template, $debug, $expectedOutput, $expectedDumped)
23+
public function testDumpTag($template, $debug, $expectedOutput, $expectedDumped)
2324
{
25+
$extension = new DumpExtension(new PhpCloner());
2426
$twig = new \Twig_Environment(new \Twig_Loader_String(), array(
2527
'debug' => $debug,
2628
'cache' => false,
2729
'optimizations' => 0,
2830
));
29-
$twig->addExtension(new DumpExtension());
31+
$twig->addExtension($extension);
3032

3133
$dumped = null;
3234
$exception = null;
@@ -46,12 +48,58 @@ public function testDebugDump($template, $debug, $expectedOutput, $expectedDumpe
4648
$this->assertSame($expectedDumped, $dumped);
4749
}
4850

49-
public function getDumpParams()
51+
public function getDumpTags()
5052
{
5153
return array(
5254
array('A{% dump %}B', true, 'AB', array()),
5355
array('A{% set foo="bar"%}B{% dump %}C', true, 'ABC', array('foo' => 'bar')),
5456
array('A{% dump %}B', false, 'AB', null),
5557
);
5658
}
59+
60+
/**
61+
* @dataProvider getDumpArgs
62+
*/
63+
public function testDump($context, $args, $expectedOutput, $debug = true)
64+
{
65+
$extension = new DumpExtension(new PhpCloner());
66+
$twig = new \Twig_Environment(new \Twig_Loader_String(), array(
67+
'debug' => $debug,
68+
'cache' => false,
69+
'optimizations' => 0,
70+
));
71+
72+
array_unshift($args, $context);
73+
array_unshift($args, $twig);
74+
75+
$dump = call_user_func_array(array($extension, 'dump'), $args);
76+
77+
if ($debug) {
78+
$this->assertStringStartsWith('<script>', $dump);
79+
$dump = preg_replace('/^.*?<pre/', '<pre', $dump);
80+
}
81+
$this->assertEquals($expectedOutput, $dump);
82+
}
83+
84+
public function getDumpArgs()
85+
{
86+
return array(
87+
array(array(), array(), '', false),
88+
array(array(), array(), "<pre id=sf-dump><span class=sf-dump-0>[]\n</span></pre><script>Sfjs.dump.instrument()</script>\n"),
89+
array(
90+
array(),
91+
array(123, 456),
92+
"<pre id=sf-dump><span class=sf-dump-0><span class=sf-dump-num>123</span>\n</span></pre><script>Sfjs.dump.instrument()</script>\n"
93+
."<pre id=sf-dump><span class=sf-dump-0><span class=sf-dump-num>456</span>\n</span></pre><script>Sfjs.dump.instrument()</script>\n",
94+
),
95+
array(
96+
array('foo' => 'bar'),
97+
array(),
98+
"<pre id=sf-dump><span class=sf-dump-0><span class=sf-dump-note>array:1</span> [<span name=sf-dump-child>\n"
99+
." <span class=sf-dump-1>\"<span class=sf-dump-meta>foo</span>\" => \"<span class=sf-dump-str>bar</span>\"\n"
100+
."</span></span>]\n"
101+
."</span></pre><script>Sfjs.dump.instrument()</script>\n",
102+
),
103+
);
104+
}
57105
}

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@
1717
<argument type="service" id="debug.stopwatch" />
1818
</service>
1919

20-
<service id="twig.extension.debug" class="Twig_Extension_Debug" public="false">
21-
<tag name="twig.extension" />
22-
</service>
23-
2420
<service id="twig.extension.dump" class="%twig.extension.dump.class%" public="false">
2521
<tag name="twig.extension" />
22+
<argument type="service" id="var_dumper.cloner" on-invalid="null" />
2623
</service>
2724
</services>
2825
</container>

src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1)
169169
$dumper->dump(
170170
$dump['data']->getLimitedClone($maxDepthLimit, $maxItemsPerDepth),
171171
function ($line, $depth) use (&$data) {
172-
if (false !==$depth) {
172+
if (-1 !== $depth) {
173173
$data .= str_repeat(' ', $depth).$line."\n";
174174
}
175175
}

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,17 @@ public function testDump()
3434

3535
$xDump = array(
3636
array(
37-
'data' => "<!DOCTYPE html><style> pre.sf-dump { background-color: #300a24; white-space: pre; line-height: 1.2em; color: #eee8d5; font-family: monospace, sans-serif; padding: 5px; } .sf-dump span { display: inline; }a.sf-dump-ref {color:#444444}span.sf-dump-num {font-weight:bold;color:#0087FF}span.sf-dump-const {font-weight:bold;color:#0087FF}span.sf-dump-str {font-weight:bold;color:#00D7FF}span.sf-dump-cchr {font-style: italic}span.sf-dump-note {color:#D7AF00}span.sf-dump-ref {color:#444444}span.sf-dump-public {color:#008700}span.sf-dump-protected {color:#D75F00}span.sf-dump-private {color:#D70000}span.sf-dump-meta {color:#005FFF}</style><pre class=sf-dump><span class=sf-dump-0><span class=sf-dump-num>123</span>\n</pre>\n",
37+
'data' => "<pre id=sf-dump><span class=sf-dump-0><span class=sf-dump-num>123</span>\n</span></pre><script>Sfjs.dump.instrument()</script>\n",
3838
'name' => 'DumpDataCollectorTest.php',
3939
'file' => __FILE__,
4040
'line' => $line,
4141
'fileExcerpt' => false,
4242
),
4343
);
44-
$this->assertSame($xDump, $collector->getDumps('html'));
44+
$dump = $collector->getDumps('html');
45+
$this->assertTrue(isset($dump[0]['data']));
46+
$dump[0]['data'] = preg_replace('/^.*?<pre/', '<pre', $dump[0]['data']);
47+
$this->assertSame($xDump, $dump);
4548

4649
$this->assertStringStartsWith(
4750
'a:1:{i:0;a:5:{s:4:"data";O:39:"Symfony\Component\VarDumper\Cloner\Data":3:{s:45:"Symfony\Component\VarDumper\Cloner\Datadata";a:1:{i:0;a:1:{i:0;i:123;}}s:49:"Symfony\Component\VarDumper\Cloner\DatamaxDepth";i:-1;s:57:"Symfony\Component\VarDumper\Cloner\DatamaxItemsPerDepth";i:-1;}s:4:"name";s:25:"DumpDataCollectorTest.php";s:4:"file";s:',

src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ public static function castReflector(\Reflector $c, array $a, Stub $stub, $isNes
2929

3030
public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested)
3131
{
32+
$stub->class = 'Closure'; // HHVM generates unique class names for closures
3233
$a = static::castReflector(new \ReflectionFunction($c), $a, $stub, $isNested);
33-
unset($a["\0+\0000"], $a['name']);
34+
unset($a["\0+\0000"], $a['name'], $a["\0+\0this"], $a["\0+\0parameter"]);
3435

3536
return $a;
3637
}

src/Symfony/Component/VarDumper/Caster/ResourceCaster.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static function castCurl($h, array $a, Stub $stub, $isNested)
2828
public static function castDba($dba, array $a, Stub $stub, $isNested)
2929
{
3030
$list = dba_list();
31-
$a['file'] = $list[substr((string) $dba, 13)];
31+
$a['file'] = $list[(int) $dba];
3232

3333
return $a;
3434
}

0 commit comments

Comments
 (0)