Skip to content

Commit 9dea601

Browse files
[DebugBundle] global dump() function for daily use
1 parent 297d373 commit 9dea601

File tree

13 files changed

+418
-2
lines changed

13 files changed

+418
-2
lines changed

composer.json

Lines changed: 6 additions & 1 deletion
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
},
@@ -83,7 +85,10 @@
8385
"src/Symfony/Component/HttpFoundation/Resources/stubs",
8486
"src/Symfony/Component/Intl/Resources/stubs"
8587
],
86-
"files": [ "src/Symfony/Component/Intl/Resources/stubs/functions.php" ]
88+
"files": [
89+
"src/Symfony/Component/Intl/Resources/stubs/functions.php",
90+
"src/Symfony/Bundle/DebugBundle/Resources/functions/debug.php"
91+
]
8792
},
8893
"minimum-stability": "dev",
8994
"extra": {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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\Bundle\DebugBundle;
13+
14+
use Symfony\Component\HttpKernel\Bundle\Bundle;
15+
use Symfony\Component\VarDumper\Dumper\CliDumper;
16+
use Symfony\Component\VarDumper\VarDumper;
17+
18+
/**
19+
* @author Nicolas Grekas <p@tchwork.com>
20+
*/
21+
class DebugBundle extends Bundle
22+
{
23+
public function boot()
24+
{
25+
if ($this->container->getParameter('kernel.debug')) {
26+
$container = $this->container;
27+
28+
// This code is here to lazy load the dump stack. This default
29+
// configuration for CLI mode is overridden in HTTP mode on
30+
// 'kernel.request' event
31+
VarDumper::setHandler(function ($var) use ($container) {
32+
$dumper = new CliDumper();
33+
$cloner = $container->get('var_dumper.cloner');
34+
$handler = function ($var) use ($dumper, $cloner) {
35+
$dumper->dump($cloner->cloneVar($var));
36+
};
37+
VarDumper::setHandler($handler);
38+
$handler($var);
39+
});
40+
}
41+
}
42+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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\Bundle\DebugBundle\DependencyInjection;
13+
14+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
15+
use Symfony\Component\Config\Definition\ConfigurationInterface;
16+
17+
/**
18+
* DebugExtension configuration structure.
19+
*
20+
* @author Nicolas Grekas <p@tchwork.com>
21+
*/
22+
class Configuration implements ConfigurationInterface
23+
{
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function getConfigTreeBuilder()
28+
{
29+
$treeBuilder = new TreeBuilder();
30+
$rootNode = $treeBuilder->root('debug');
31+
32+
$rootNode
33+
->children()
34+
->integerNode('max_items')
35+
->info('Max number of displayed items past the first level, -1 means no limit')
36+
->min(-1)
37+
->defaultValue(250)
38+
->end()
39+
->integerNode('max_string_length')
40+
->info('Max length of displayed strings, -1 means no limit')
41+
->min(-1)
42+
->defaultValue(-1)
43+
->end()
44+
->end();
45+
46+
return $treeBuilder;
47+
}
48+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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\Bundle\DebugBundle\DependencyInjection;
13+
14+
use Symfony\Component\Config\FileLocator;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
17+
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
18+
19+
/**
20+
* DebugExtension.
21+
*
22+
* @author Nicolas Grekas <p@tchwork.com>
23+
*/
24+
class DebugExtension extends Extension
25+
{
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function load(array $configs, ContainerBuilder $container)
30+
{
31+
$configuration = new Configuration();
32+
$config = $this->processConfiguration($configuration, $configs);
33+
34+
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
35+
$loader->load('services.xml');
36+
37+
$container->setParameter(
38+
'var_dumper.cloner.class',
39+
'Symfony\Component\VarDumper\Cloner\\'.(function_exists('symfony_zval_info') ? 'Ext' : 'Php').'Cloner'
40+
);
41+
42+
$container->getDefinition('var_dumper.cloner')
43+
->addMethodCall('setMaxItems', array($config['max_items']))
44+
->addMethodCall('setMaxString', array($config['max_string_length']));
45+
}
46+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
dump() function
2+
================
3+
4+
This bundle provides a better `dump()` function, that you can use instead of
5+
`var_dump()`, *better* meaning:
6+
7+
- per object and resource types specialized view: e.g. filter out Doctrine noise
8+
while dumping a single proxy entity, or get more insight on opened files with
9+
`stream_get_meta_data()`. Add your own dedicated `Dumper\Caster` and get the
10+
view *you* need.
11+
- configurable output format: HTML, command line with colors or [a dedicated high
12+
accuracy JSON format](Resource/doc/json-spec.md).
13+
- ability to dump internal references, either soft ones (objects or resources)
14+
or hard ones (`=&` on arrays or objects properties). Repeated occurrences of
15+
the same object/array/resource won't appear again and again anymore. Moreover,
16+
you'll be able to inspect the reference structure of your data.
17+
- ability to operate in the context of an output buffering handler.
18+
- full exposure of the internal mechanisms used for walking through an arbitrary
19+
PHP data structure.
20+
21+
Calling `dump($myVvar)` works in all PHP code and `{% dump myVar %}` or
22+
`{{ dump(myVar) }}` in Twig templates.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<parameters>
8+
<parameter key="data_collector.dump.class">Symfony\Component\HttpKernel\DataCollector\DumpDataCollector</parameter>
9+
<parameter key="debug.dump_listener.class">Symfony\Component\HttpKernel\EventListener\DumpListener</parameter>
10+
</parameters>
11+
12+
<services>
13+
<service id="data_collector.dump" class="%data_collector.dump.class%">
14+
<tag name="data_collector" id="dump" template="@Debug/Profiler/dump.html.twig" />
15+
<argument type="service" id="debug.stopwatch" on-invalid="ignore" />
16+
</service>
17+
18+
<service id="debug.dump_listener" class="%debug.dump_listener.class%">
19+
<tag name="kernel.event_subscriber" />
20+
<argument type="service" id="service_container" />
21+
<argument>data_collector.dump</argument>
22+
</service>
23+
24+
<service id="var_dumper.cloner" class="%var_dumper.cloner.class%" />
25+
</services>
26+
27+
</container>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2004-2014 Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
2+
3+
{% block toolbar %}
4+
{% set dumps_count = collector.dumpsCount %}
5+
6+
{% if dumps_count %}
7+
{% set icon %}
8+
<img alt="dump()" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAcCAYAAACOGPReAAACcUlEQVRIx+1UPUwUYRB97+Pc8ychMSaE4E+BrYWVgCd7e5dYQSxoiIFEjYWVdNiJiVjaSGFhowUkhsLEH2Jhcvsd54nYaQ0USoAYG7WBvWOfhd+R87zFC40N00z2zTdv30xmBti3/2ZBECy3+pZJgXw+f0rSiKQBkt2SOkluSFoh+SqKoplyufylJdIgCNIAJgGMkUzXcEkAEJM0DtqUNAVgwlq7Vc9hGtR1ACiSHCeZlvQGwFClUjkKYAVAexzHFyXNAkiTvEXSury/lTqFRZI9kr4DuGKtfV6L53K5tTAMu+reZwDMkuwC8F5SUFNcr3TSEf4g6dcTuvIP139ba8vGmD5JawB6Adz9o/xMJnMSwJhLvhGG4acm/T/UCBQKhc9xHA8DAMkxx/Ob1PO8UdfDD8Vi8WnCQAw1A+fn599KegbgoOd5Izukkgbc354kjZi1di4pJumx84M7pCRPO/DdXhaD5ILz3QDAXC4XATiQ8H48DMP7jWA2mx00xrxMUB3Rjcs6gE5JZ621H/ewwsdIfgOwHoZhV22klpz883spX1Kf80v1czrnwKtJidlsdnCXnl6r5zEAUK1WpwFskjwXBMFws8SkHvq+f4HkEIDN7e3tmR3SUqm06o4DADzyff9MK2X39/efMMbU5vpBqVRabVzTCUmLJNvb2tpKu5XrFPamUqkFksfd7t9pevry+XxHHMcvSPa4Hr+W9LBarVrP836mUqkjlUqlF8B1kpcBUNKiMeZSoVD4+q97eg/Azdo9lRSTNDXvsC0AUwBuN97TXS9/HMejAAbcpnQC2JC0THIuiqLppMvfsrnN27d/2y+hkCBqr75LOwAAAABJRU5ErkJggg==" />
9+
<span class="sf-toolbar-status sf-toolbar-status-yellow">{{ dumps_count }}</span>
10+
{% endset %}
11+
12+
{% set text %}
13+
<div style="width: 450px; overflow: hidden;">
14+
<div class="sf-toolbar-info-piece">
15+
<b>dump()</b>
16+
</div>
17+
{% for dump in collector.getDumps('html') %}
18+
<div class="sf-toolbar-info-piece">
19+
in {% if dump.file %}<abbr title="{{ dump.file }}">{{ dump.name }}</abbr>{% else %}{{ dump.name }}{% endif %}
20+
line {{ dump.line }}:
21+
{{ dump.data|raw }}
22+
</div>
23+
{% endfor %}
24+
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" onload="var h = this.parentNode.innerHTML, rx=/<script>(.*?)<\/script>/g, s; while (s = rx.exec(h)) {eval(s[1]);};" />
25+
</div>
26+
{% endset %}
27+
28+
{% include '@WebProfiler/Profiler/toolbar_item.html.twig' with { 'link': true } %}
29+
{% endif %}
30+
{% endblock %}
31+
32+
{% block menu %}
33+
<span class="label">
34+
<span class="icon">
35+
{{- "" -}}
36+
<img alt="dump()" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAADdUlEQVRIx71WPWwcVRD+ZneN3NzKiAgiJIrwZ9EQ2xchI+/uvb0g8SOouGtAKQAnSkHSJCZF6jSBUCQFkoNEEILGoaDCQVzeu1sLgeAI4cdyBE2qEMtE6LZA2bvbScGcWRt77+wYpntv5833vu/NzgywDVNK3VZK3d7OWRoQYC+ACgCfiEYB7JZPvzPzNQARgIvGmKt3Bej7/rjjOG8D2D8ggVqn05mJoujKlgCLxaJTKBTOENGRdT5LAH4D8KKsPwUwAWBPxoeZ+Vwcx8eazWZnfWxr/YbneSOu684T0VEB+4uZT3e73ce01k8w8+Ger9a6orV+mJn3AbjAzCkAIqKjruvOe543kstQmF0iorJc9TKA140x13s+5XL5fma+KYBrzgdBsM+yrI+J6PGexK1W67ks0zUMRcayLC/EcfxsFgwAkiRJNnufRqPxnW3bTzPzV7K1v1AonNlQ0jAMJ+TNAGCemac3egPHcdq5WVOr3bJt+yUAv+JvfY/4vj++EcPTIvGf7Xb7gDGmu1HA5eXlpG+q1mq3mPkAAAZAkun/AAZBMJZJ/VMLCwsrmwVbXFxsp2l6ME3Tg3mgxphvAHzSkzYMwycBwAEA27YrkiQJgA/6MajX6+8P+F/OAnhVYlcB/GjJwhe9I2PMH9gh01o3APTU8rNvOCrAV7DzdlXIjAIAhWGYABjKO5Gm6fP1en0+zycMw8MA3svzYebEwv9sJLe7AWA3M79jjJnZSYAwDL+UP+CG1vpBK1OUQUTj/wGpvSLn0mrSMHPUy1al1H07yC4AsEvINFYBu93unGzeQ0Sv9QtUKpWmS6XS9ACYhzIJM7cKGEXRT8z8hXw76XnerrwolmWdtyzrfB92TwF4RZaXjDG/rKmlaZqekNo34jjOh9VqddsZPDk5eS8zfwSAmDll5hP/Kt6NRuMHAGdF2hdWVlZmi8Wis1Uwz/NGhoeHP8v0xLPZWWcNi1ardVyaLgC84bru51NTUw8NCiYz0NdE5PcaRxzHM5uOGM1ms9PpdF7OgD4zNDS0pJQ6pZR6JG+qU0rN2rb9ba+EMfPldrtdWd9T84aod4nozYwPA1hi5p+JqCp7FwGMAXh00CGK+mTahDTmgcdEAG9prb+/q0E4CIIx27Yr0sZGiegBoXITwDUiiph5bpBBeLsVJJEus2W7A2Z3gfLvF5gPAAAAAElFTkSuQmCC" />
37+
{{- "" -}}
38+
</span>
39+
<strong>dump()</strong>
40+
<span class="count">
41+
<span>{{ collector.dumpsCount }}</span>
42+
</span>
43+
</span>
44+
{% endblock %}
45+
46+
{% block panel %}
47+
<h2>dump()</h2>
48+
49+
<style>
50+
li.sf-dump {
51+
list-style-type: disc;
52+
}
53+
.sf-dump ol>li {
54+
padding: 0;
55+
}
56+
.sf-dump a {
57+
cursor: pointer;
58+
}
59+
.sf-dump-compact {
60+
display: none;
61+
}
62+
</style>
63+
64+
<ul class="alt">
65+
{% for dump in collector.getDumps('html') %}
66+
<li class="sf-dump sf-reset">
67+
in {% if dump.file %}<abbr title="{{ dump.file }}">{{ dump.name }}</abbr>{% else %}{{ dump.name }}{% endif %}
68+
line {{ dump.line }}:
69+
<a onclick="Sfjs.dump.toggle(this)">▶</a>
70+
<span class="sf-dump-compact">
71+
{% if dump.fileExcerpt %}{{ dump.fileExcerpt|raw }}{% else %}{{ dump.file|file_excerpt(dump.line) }}{% endif %}
72+
</span>
73+
74+
{{ dump.data|raw }}
75+
</li>
76+
{% endfor %}
77+
</ul>
78+
{% endblock %}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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\Bundle\DebugBundle\Tests\DependencyInjection;
13+
14+
use Symfony\Bundle\DebugBundle\DependencyInjection\DebugExtension;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
17+
18+
class DebugExtensionTest extends \PHPUnit_Framework_TestCase
19+
{
20+
public function testLoadWithoutConfiguration()
21+
{
22+
$container = $this->createContainer();
23+
$container->registerExtension(new DebugExtension());
24+
$container->loadFromExtension('debug', array());
25+
$this->compileContainer($container);
26+
27+
$expectedTags = array(
28+
array(
29+
"id" => "dump",
30+
"template" => "@Debug/Profiler/dump.html.twig",
31+
),
32+
);
33+
34+
$this->assertSame($expectedTags, $container->getDefinition('data_collector.dump')->getTag('data_collector'));
35+
}
36+
37+
private function createContainer()
38+
{
39+
$container = new ContainerBuilder(new ParameterBag(array(
40+
'kernel.cache_dir' => __DIR__,
41+
'kernel.root_dir' => __DIR__.'/Fixtures',
42+
'kernel.charset' => 'UTF-8',
43+
'kernel.debug' => true,
44+
'kernel.bundles' => array('DebugBundle' => 'Symfony\\Bundle\\DebugBundle\\DebugBundle'),
45+
)));
46+
47+
return $container;
48+
}
49+
50+
private function compileContainer(ContainerBuilder $container)
51+
{
52+
$container->getCompilerPassConfig()->setOptimizationPasses(array());
53+
$container->getCompilerPassConfig()->setRemovingPasses(array());
54+
$container->compile();
55+
}
56+
}

0 commit comments

Comments
 (0)