Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1b49368

Browse files
committed
feature#10640 VarDumper and DebugBundle (jpauli, nicolas-grekas, ruian, moux2003, tony-co, romainneutron, oscherler, lyrixx)
This PR was merged into the 2.6-dev branch.Discussion----------VarDumper and DebugBundle| Q | A| ------------- | ---| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | none| License | MIT| Doc PR | noneFrom a user land point of view, this PR creates a global `dump()` function that is to be used instead of `var_dump()`. The component can be used standalone in any dev workflow. Please see the [provided README](https://github.com/symfony/symfony/pull/10640/files?short_path=52d526f#diff-52d526f19bc9e3825c80e7694755409c) for details.When used with the Framework bundle, variables passed to `dump()` are dumped in a new dedicated panel in the web toolbar. The function is also available in twig templates.Regarding the implementation, I'm pretty sure you'll find a lot to comment. As I'm sure of nothing else, not even the names of things, please do.I tried to organize this PR in several commits, from the most fundamental algorithm to pure Symfony glue.I suggest you follow this order while progressing in the review and the discussion around this PR, so that we can together validate commits one after the other.Don't hesitate to fork the PR and submit PR on it, I'll cherry-pick your patches.TODO:- [x] open a doc PR:symfony/symfony-docs#4243- [x] open a PR on the Standard edition:symfony/symfony-standard#710- [x] prefix the CSS classes- [x] tests for the DebugBundle + other Symfony glue classes- [x] inline css and js for compat with e.g. Silex- [x] finish and merge nicolas-grekas/Patchwork-Dumper#5 for better UX- [x] show a dump excerpt on hovering the icon in the toolbar- [x] verify README and comments- [x] validate interfaces/names (Caster / Cloner / Dumper)- [x] validate new VarDumper component + DebugBundle- [x] validate Resource/ext/ vs independent repos.- [x] test and define behavior after KernelEvents::RESPONSE- [x] update dependencies between components/bundles and composer.json files- [x] no hard dep on iconvNot for this PR but might be worth later:- show a light stack trace + timing + memory at debug() calls- create a "theme" concept for custom colors/UXCommits-------80fd736 [DebugBundle] Enhance some comments2e167ba [TwigBridge] add Twig dump() function + tests and fixes0f8d30f [VarDumper] Replace \e with \x1B in CliDumper to support colour in PHP < 5.4d43ae82 [VarDumper] Add workaround tohttps://bugs.php.net/65967a8d81e4 [DebugBundle] Inlined assets to avoid installation issues5f59811 [DebugBundle] Add doc example for Twig usagee4e00ef [TwigBridge] DumpNode and Token parserde05cd9 [DebugBundle] enhance dump excerpts49f13c6 [HttpKernel] add tests for DumpDataCollector081363c [HttpKernel] tests for DumpListener0d8a942 [VarDumper] add Stub objects for cutting cleanly and dumping constsc8746a4 [DebugBundle] add tests for twig and for the bundle8d5d970 [DebugBundle] adjust after revieweb98c81 [DebugBundle] dump() + better Symfony glue9dea601 [DebugBundle] global dump() function for daily use297d373 [VarDumper] README, LICENSE and composer.jsona69e962 [VarDumper] tests for HtmlDumper5eaa187 [VarDumper] tests for CliDumpere6dde33 [VarDumper] HTML variant of the CLI dumperfa81544 [VarDumper] CLI dedicated dumper and related abstract1d5e3f4 [VarDumper] interface for dumping collected variables0266072 [VarDumper] casters for DOM objectsc426d8b [VarDumper] casters for Doctrine objects0a92c08 [VarDumper] casters for PDO related objectsda3e50a [VarDumper] casters for SPL data structuresc91bc83 [VarDumper] casters for exceptions representation3ddbf4b [VarDumper] add casters for per class/resource custom state extraction5b7ae28 [VarDumper] symfony_debug ext. fast and memory efficient cloning algo07135a0 [VarDumper] algo to clone any PHP variable to a breadth-first queue4bf9300 [Debug] a README for the debug extensioneec5c92 [Debug] Symfony debug extension
2 parentsea6ce1c +80fd736 commit1b49368

File tree

60 files changed

+5209
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+5209
-1
lines changed

‎composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"symfony/css-selector":"self.version",
3131
"symfony/dependency-injection":"self.version",
3232
"symfony/debug":"self.version",
33+
"symfony/debug-bundle":"self.version",
3334
"symfony/doctrine-bridge":"self.version",
3435
"symfony/dom-crawler":"self.version",
3536
"symfony/event-dispatcher":"self.version",
@@ -63,6 +64,7 @@
6364
"symfony/twig-bridge":"self.version",
6465
"symfony/twig-bundle":"self.version",
6566
"symfony/validator":"self.version",
67+
"symfony/var-dumper":"self.version",
6668
"symfony/web-profiler-bundle":"self.version",
6769
"symfony/yaml":"self.version"
6870
},
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
namespaceSymfony\Bridge\Twig\Extension;
13+
14+
useSymfony\Bridge\Twig\TokenParser\DumpTokenParser;
15+
useSymfony\Component\VarDumper\Cloner\ClonerInterface;
16+
useSymfony\Component\VarDumper\Dumper\HtmlDumper;
17+
18+
/**
19+
* Provides integration of the dump() function with Twig.
20+
*
21+
* @author Nicolas Grekas <p@tchwork.com>
22+
*/
23+
class DumpExtensionextends \Twig_Extension
24+
{
25+
publicfunction__construct(ClonerInterface$cloner =null)
26+
{
27+
$this->cloner =$cloner;
28+
}
29+
30+
publicfunctiongetFunctions()
31+
{
32+
returnarray(
33+
new \Twig_SimpleFunction('dump',array($this,'dump'),array('is_safe' =>array('html'),'needs_context' =>true,'needs_environment' =>true)),
34+
);
35+
}
36+
37+
publicfunctiongetTokenParsers()
38+
{
39+
returnarray(newDumpTokenParser());
40+
}
41+
42+
publicfunctiongetName()
43+
{
44+
return'dump';
45+
}
46+
47+
publicfunctiondump(\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 ($contextas$key =>$value) {
56+
if (!$valueinstanceof \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 =newHtmlDumper(function ($line,$depth)use (&$html) {
69+
if (-1 !==$depth) {
70+
$html .=str_repeat('',$depth).$line."\n";
71+
}
72+
});
73+
74+
foreach ($varsas$value) {
75+
$dumper->dump($this->cloner->cloneVar($value));
76+
}
77+
78+
return$html;
79+
}
80+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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+
namespaceSymfony\Bridge\Twig\Node;
13+
14+
/**
15+
* @author Julien Galenski <julien.galenski@gmail.com>
16+
*/
17+
class DumpNodeextends \Twig_Node
18+
{
19+
private$varPrefix;
20+
21+
publicfunction__construct($varPrefix,\Twig_NodeInterface$values =null,$lineno,$tag =null)
22+
{
23+
parent::__construct(array('values' =>$values),array(),$lineno,$tag);
24+
$this->varPrefix =$varPrefix;
25+
}
26+
27+
/**
28+
* {@inheritdoc}
29+
*/
30+
publicfunctioncompile(\Twig_Compiler$compiler)
31+
{
32+
$compiler
33+
->write("if (\$this->env->isDebug()) {\n")
34+
->indent();
35+
36+
$values =$this->getNode('values');
37+
38+
if (null ===$values) {
39+
// remove embedded templates (macros) from the context
40+
$compiler
41+
->write(sprintf('$%svars = array();'."\n",$this->varPrefix))
42+
->write(sprintf('foreach ($context as $%1$skey => $%1$sval) {'."\n",$this->varPrefix))
43+
->indent()
44+
->write(sprintf('if (!$%sval instanceof \Twig_Template) {'."\n",$this->varPrefix))
45+
->indent()
46+
->write(sprintf('$%1$svars[$%1$skey] = $%1$sval;'."\n",$this->varPrefix))
47+
->outdent()
48+
->write("}\n")
49+
->outdent()
50+
->write("}\n")
51+
->addDebugInfo($this)
52+
->write(sprintf('\Symfony\Component\VarDumper\VarDumper::dump($%svars);'."\n",$this->varPrefix));
53+
}elseif (1 ===$values->count()) {
54+
$compiler
55+
->addDebugInfo($this)
56+
->write('\Symfony\Component\VarDumper\VarDumper::dump(')
57+
->subcompile($values->getNode(0))
58+
->raw(");\n");
59+
}else {
60+
$compiler
61+
->addDebugInfo($this)
62+
->write('\Symfony\Component\VarDumper\VarDumper::dump(array('."\n")
63+
->indent();
64+
foreach ($valuesas$node) {
65+
$compiler->addIndentation();
66+
if ($node->hasAttribute('name')) {
67+
$compiler
68+
->string($node->getAttribute('name'))
69+
->raw(' =>');
70+
}
71+
$compiler
72+
->subcompile($node)
73+
->raw(",\n");
74+
}
75+
$compiler
76+
->outdent()
77+
->write("));\n");
78+
}
79+
80+
$compiler
81+
->outdent()
82+
->raw("}\n");
83+
}
84+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
namespaceSymfony\Bridge\Twig\Tests\Extension;
13+
14+
useSymfony\Bridge\Twig\Extension\DumpExtension;
15+
useSymfony\Component\VarDumper\VarDumper;
16+
useSymfony\Component\VarDumper\Cloner\PhpCloner;
17+
18+
class DumpExtensionTestextends \PHPUnit_Framework_TestCase
19+
{
20+
/**
21+
* @dataProvider getDumpTags
22+
*/
23+
publicfunctiontestDumpTag($template,$debug,$expectedOutput,$expectedDumped)
24+
{
25+
$extension =newDumpExtension(newPhpCloner());
26+
$twig =new \Twig_Environment(new \Twig_Loader_String(),array(
27+
'debug' =>$debug,
28+
'cache' =>false,
29+
'optimizations' =>0,
30+
));
31+
$twig->addExtension($extension);
32+
33+
$dumped =null;
34+
$exception =null;
35+
$prevDumper = VarDumper::setHandler(function ($var)use (&$dumped) {$dumped =$var;});
36+
37+
try {
38+
$this->assertEquals($expectedOutput,$twig->render($template));
39+
}catch (\Exception$exception) {
40+
}
41+
42+
VarDumper::setHandler($prevDumper);
43+
44+
if (null !==$exception) {
45+
throw$exception;
46+
}
47+
48+
$this->assertSame($expectedDumped,$dumped);
49+
}
50+
51+
publicfunctiongetDumpTags()
52+
{
53+
returnarray(
54+
array('A{% dump %}B',true,'AB',array()),
55+
array('A{% set foo="bar"%}B{% dump %}C',true,'ABC',array('foo' =>'bar')),
56+
array('A{% dump %}B',false,'AB',null),
57+
);
58+
}
59+
60+
/**
61+
* @dataProvider getDumpArgs
62+
*/
63+
publicfunctiontestDump($context,$args,$expectedOutput,$debug =true)
64+
{
65+
$extension =newDumpExtension(newPhpCloner());
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+
publicfunctiongetDumpArgs()
85+
{
86+
returnarray(
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+
}
105+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
namespaceSymfony\Bridge\Twig\Tests\Node;
13+
14+
useSymfony\Bridge\Twig\Node\DumpNode;
15+
16+
class DumpNodeTestextends \PHPUnit_Framework_TestCase
17+
{
18+
publicfunctiontestNoVar()
19+
{
20+
$node =newDumpNode('bar',null,7);
21+
22+
$env =new \Twig_Environment();
23+
$compiler =new \Twig_Compiler($env);
24+
25+
$expected = <<<'EOTXT'
26+
if ($this->env->isDebug()) {
27+
$barvars = array();
28+
foreach ($context as $barkey => $barval) {
29+
if (!$barval instanceof \Twig_Template) {
30+
$barvars[$barkey] = $barval;
31+
}
32+
}
33+
// line 7
34+
\Symfony\Component\VarDumper\VarDumper::dump($barvars);
35+
}
36+
37+
EOTXT;
38+
39+
$this->assertSame($expected,$compiler->compile($node)->getSource());
40+
}
41+
42+
publicfunctiontestOneVar()
43+
{
44+
$vars =new \Twig_Node(array(
45+
new \Twig_Node_Expression_Name('foo',7),
46+
));
47+
$node =newDumpNode('bar',$vars,7);
48+
49+
$env =new \Twig_Environment();
50+
$compiler =new \Twig_Compiler($env);
51+
52+
$expected = <<<'EOTXT'
53+
if ($this->env->isDebug()) {
54+
// line 7
55+
\Symfony\Component\VarDumper\VarDumper::dump(%foo%);
56+
}
57+
58+
EOTXT;
59+
$expected =preg_replace('/%(.*?)%/',version_compare(PHP_VERSION,'5.4.0') >=0 ?'(isset($context["$1"]) ? $context["$1"] : null)' :'$this->getContext($context, "$1")',$expected);
60+
61+
$this->assertSame($expected,$compiler->compile($node)->getSource());
62+
}
63+
64+
publicfunctiontestMultiVars()
65+
{
66+
$vars =new \Twig_Node(array(
67+
new \Twig_Node_Expression_Name('foo',7),
68+
new \Twig_Node_Expression_Name('bar',7),
69+
));
70+
$node =newDumpNode('bar',$vars,7);
71+
72+
$env =new \Twig_Environment();
73+
$compiler =new \Twig_Compiler($env);
74+
75+
$expected = <<<'EOTXT'
76+
if ($this->env->isDebug()) {
77+
// line 7
78+
\Symfony\Component\VarDumper\VarDumper::dump(array(
79+
"foo" => %foo%,
80+
"bar" => %bar%,
81+
));
82+
}
83+
84+
EOTXT;
85+
$expected =preg_replace('/%(.*?)%/',version_compare(PHP_VERSION,'5.4.0') >=0 ?'(isset($context["$1"]) ? $context["$1"] : null)' :'$this->getContext($context, "$1")',$expected);
86+
87+
$this->assertSame($expected,$compiler->compile($node)->getSource());
88+
}
89+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp