[DebugBundle] dump() + better Symfony glue
This commit is contained in:
parent
9dea601234
commit
eb98c81754
|
@ -87,7 +87,7 @@
|
||||||
],
|
],
|
||||||
"files": [
|
"files": [
|
||||||
"src/Symfony/Component/Intl/Resources/stubs/functions.php",
|
"src/Symfony/Component/Intl/Resources/stubs/functions.php",
|
||||||
"src/Symfony/Bundle/DebugBundle/Resources/functions/debug.php"
|
"src/Symfony/Bundle/DebugBundle/Resources/functions/dump.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Twig\Extension;
|
||||||
|
|
||||||
|
use Symfony\Bridge\Twig\TokenParser\DumpTokenParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides integration of the dump() function with Twig.
|
||||||
|
*
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
class DumpExtension extends \Twig_Extension
|
||||||
|
{
|
||||||
|
public function getTokenParsers()
|
||||||
|
{
|
||||||
|
return array(new DumpTokenParser());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'dump';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Twig\Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Julien Galenski <julien.galenski@gmail.com>
|
||||||
|
*/
|
||||||
|
class DumpNode extends \Twig_Node
|
||||||
|
{
|
||||||
|
public function __construct(\Twig_NodeInterface $values = null, $lineno, $tag = null)
|
||||||
|
{
|
||||||
|
parent::__construct(array('values' => $values), array(), $lineno, $tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function compile(\Twig_Compiler $compiler)
|
||||||
|
{
|
||||||
|
$compiler
|
||||||
|
->write("if (\$this->env->isDebug()) {\n")
|
||||||
|
->indent()
|
||||||
|
;
|
||||||
|
|
||||||
|
$values = $this->getNode('values');
|
||||||
|
|
||||||
|
if (null === $values) {
|
||||||
|
// remove embedded templates (macros) from the context
|
||||||
|
$compiler
|
||||||
|
->write("\$vars = array();\n")
|
||||||
|
->write("foreach (\$context as \$key => \$value) {\n")
|
||||||
|
->indent()
|
||||||
|
->write("if (!\$value instanceof Twig_Template) {\n")
|
||||||
|
->indent()
|
||||||
|
->write("\$vars[\$key] = \$value;\n")
|
||||||
|
->outdent()
|
||||||
|
->write("}\n")
|
||||||
|
->outdent()
|
||||||
|
->write("}\n")
|
||||||
|
->addDebugInfo($this)
|
||||||
|
->write('\Symfony\Component\Debug\Debug::dump($vars);'."\n")
|
||||||
|
;
|
||||||
|
} elseif (1 === $values->count()) {
|
||||||
|
$compiler
|
||||||
|
->addDebugInfo($this)
|
||||||
|
->write('\Symfony\Component\Debug\Debug::dump(')
|
||||||
|
->subcompile($values->getNode(0))
|
||||||
|
->raw(");\n")
|
||||||
|
;
|
||||||
|
} else {
|
||||||
|
$compiler
|
||||||
|
->addDebugInfo($this)
|
||||||
|
->write('\Symfony\Component\Debug\Debug::dump(array(')
|
||||||
|
->indent()
|
||||||
|
;
|
||||||
|
foreach ($values as $node) {
|
||||||
|
$compiler->addIndentation();
|
||||||
|
if ($node->hasAttribute('name')) {
|
||||||
|
$compiler
|
||||||
|
->string($node->getAttribute('name'))
|
||||||
|
->raw(' => ')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
$compiler
|
||||||
|
->subcompile($node)
|
||||||
|
->raw(",\n")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
$compiler
|
||||||
|
->outdent()
|
||||||
|
->raw("));\n")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
$compiler
|
||||||
|
->outdent()
|
||||||
|
->write("}\n")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Twig\TokenParser;
|
||||||
|
|
||||||
|
use Symfony\Bridge\Twig\Node\DumpNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token Parser for the 'dump' tag.
|
||||||
|
*
|
||||||
|
* Dump variables with:
|
||||||
|
* <pre>
|
||||||
|
* {% dump %}
|
||||||
|
* {% dump foo %}
|
||||||
|
* {% dump foo, bar %}
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author Julien Galenski <julien.galenski@gmail.com>
|
||||||
|
*/
|
||||||
|
class DumpTokenParser extends \Twig_TokenParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function parse(\Twig_Token $token)
|
||||||
|
{
|
||||||
|
$values = null;
|
||||||
|
if (!$this->parser->getStream()->test(\Twig_Token::BLOCK_END_TYPE)) {
|
||||||
|
$values = $this->parser->getExpressionParser()->parseMultitargetExpression();
|
||||||
|
}
|
||||||
|
$this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE);
|
||||||
|
|
||||||
|
return new DumpNode($values, $token->getLine(), $this->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getTag()
|
||||||
|
{
|
||||||
|
return 'dump';
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,7 @@
|
||||||
"symfony/security": "~2.4",
|
"symfony/security": "~2.4",
|
||||||
"symfony/stopwatch": "~2.2",
|
"symfony/stopwatch": "~2.2",
|
||||||
"symfony/console": "~2.2",
|
"symfony/console": "~2.2",
|
||||||
|
"symfony/var-dumper": "~2.6",
|
||||||
"symfony/expression-language": "~2.4"
|
"symfony/expression-language": "~2.4"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
"symfony/yaml": "For using the YamlExtension",
|
"symfony/yaml": "For using the YamlExtension",
|
||||||
"symfony/security": "For using the SecurityExtension",
|
"symfony/security": "For using the SecurityExtension",
|
||||||
"symfony/stopwatch": "For using the StopwatchExtension",
|
"symfony/stopwatch": "For using the StopwatchExtension",
|
||||||
|
"symfony/var-dumper": "For using the DumpExtension",
|
||||||
"symfony/expression-language": "For using the ExpressionExtension"
|
"symfony/expression-language": "For using the ExpressionExtension"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
|
|
||||||
namespace Symfony\Component\Debug;
|
namespace Symfony\Component\Debug;
|
||||||
|
|
||||||
|
use Symfony\Component\VarDumper\Cloner\ExtCloner;
|
||||||
|
use Symfony\Component\VarDumper\Cloner\PhpCloner;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers all the debug tools.
|
* Registers all the debug tools.
|
||||||
*
|
*
|
||||||
|
@ -19,6 +24,7 @@ namespace Symfony\Component\Debug;
|
||||||
class Debug
|
class Debug
|
||||||
{
|
{
|
||||||
private static $enabled = false;
|
private static $enabled = false;
|
||||||
|
private static $dumpHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables the debug tools.
|
* Enables the debug tools.
|
||||||
|
@ -59,4 +65,42 @@ class Debug
|
||||||
|
|
||||||
DebugClassLoader::enable();
|
DebugClassLoader::enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function dump($var)
|
||||||
|
{
|
||||||
|
if (null === self::$dumpHandler) {
|
||||||
|
$cloner = extension_loaded('symfony_debug') ? new ExtCloner() : new PhpCloner();
|
||||||
|
$dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper();
|
||||||
|
self::$dumpHandler = function ($var) use ($cloner, $dumper) {
|
||||||
|
$dumper->dump($cloner->cloneVar($var));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
$h = self::$dumpHandler;
|
||||||
|
|
||||||
|
if (is_array($h)) {
|
||||||
|
return $h[0]->{$h[1]}($var);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $h($var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setDumpHandler($callable)
|
||||||
|
{
|
||||||
|
if (!is_callable($callable)) {
|
||||||
|
throw new \InvalidArgumentException('Invalid PHP callback.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$prevHandler = self::$dumpHandler;
|
||||||
|
|
||||||
|
if (is_array($callable)) {
|
||||||
|
if (!is_object($callable[0])) {
|
||||||
|
self::$dumpHandler = $callable[0].'::'.$callable[1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self::$dumpHandler = $callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $prevHandler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,12 @@
|
||||||
"psr/log": "~1.0"
|
"psr/log": "~1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"symfony/var-dumper": "~2.6",
|
||||||
"symfony/http-kernel": "~2.1",
|
"symfony/http-kernel": "~2.1",
|
||||||
"symfony/http-foundation": "~2.1"
|
"symfony/http-foundation": "~2.1"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
"symfony/var-dumper": "For using Debug::dump()",
|
||||||
"symfony/http-foundation": "",
|
"symfony/http-foundation": "",
|
||||||
"symfony/http-kernel": ""
|
"symfony/http-kernel": ""
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Stopwatch\Stopwatch;
|
||||||
|
use Symfony\Component\VarDumper\Cloner\Data;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\JsonDumper;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
class DumpDataCollector extends DataCollector implements DataDumperInterface
|
||||||
|
{
|
||||||
|
private $stopwatch;
|
||||||
|
private $isCollected = true;
|
||||||
|
private $clonesRoot;
|
||||||
|
private $clonesCount = 0;
|
||||||
|
|
||||||
|
public function __construct(Stopwatch $stopwatch = null)
|
||||||
|
{
|
||||||
|
$this->stopwatch = $stopwatch;
|
||||||
|
$this->clonesRoot = $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
$this->data = array();
|
||||||
|
$this->clonesRoot->clonesCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dump(Data $data)
|
||||||
|
{
|
||||||
|
if ($this->stopwatch) {
|
||||||
|
$this->stopwatch->start('dump');
|
||||||
|
}
|
||||||
|
if ($this->clonesRoot->isCollected) {
|
||||||
|
$this->clonesRoot->isCollected = false;
|
||||||
|
register_shutdown_function(array($this->clonesRoot, 'flushDumps'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$trace = PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS : true;
|
||||||
|
if (PHP_VERSION_ID >= 50400) {
|
||||||
|
$trace = debug_backtrace($trace, 6);
|
||||||
|
} else {
|
||||||
|
$trace = debug_backtrace($trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $trace[0]['file'];
|
||||||
|
$line = $trace[0]['line'];
|
||||||
|
$name = false;
|
||||||
|
$fileExcerpt = false;
|
||||||
|
|
||||||
|
for ($i = 1; $i < 6; ++$i) {
|
||||||
|
if (isset($trace[$i]['class'], $trace[$i]['function'])
|
||||||
|
&& 'dump' === $trace[$i]['function']
|
||||||
|
&& 'Symfony\Bundle\DebugBundle\DebugBundle' === $trace[$i]['class']
|
||||||
|
) {
|
||||||
|
$file = $trace[$i]['file'];
|
||||||
|
$line = $trace[$i]['line'];
|
||||||
|
|
||||||
|
while (++$i < 6) {
|
||||||
|
if (isset($trace[$i]['function']) && empty($trace[$i]['class'])) {
|
||||||
|
$file = $trace[$i]['file'];
|
||||||
|
$line = $trace[$i]['line'];
|
||||||
|
break;
|
||||||
|
} elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof \Twig_Template) {
|
||||||
|
$info = $trace[$i]['object'];
|
||||||
|
$name = $info->getTemplateName();
|
||||||
|
$src = $info->getEnvironment()->getLoader()->getSource($name);
|
||||||
|
$info = $info->getDebugInfo();
|
||||||
|
if (isset($info[$trace[$i-1]['line']])) {
|
||||||
|
$file = false;
|
||||||
|
$line = $info[$trace[$i-1]['line']];
|
||||||
|
$src = explode("\n", $src);
|
||||||
|
$fileExcerpt = array();
|
||||||
|
|
||||||
|
for ($i = max($line - 3, 1), $max = min($line + 3, count($src)); $i <= $max; ++$i) {
|
||||||
|
$fileExcerpt[] = '<li'.($i === $line ? ' class="selected"' : '').'><code>'.htmlspecialchars($src[$i - 1]).'</code></li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileExcerpt = '<ol start="'.max($line - 3, 1).'">'.implode("\n", $fileExcerpt).'</ol>';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $name) {
|
||||||
|
$name = strtr($file, '\\', '/');
|
||||||
|
$name = substr($file, strrpos($file, '/') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->clonesRoot->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt');
|
||||||
|
|
||||||
|
if ($this->stopwatch) {
|
||||||
|
$this->stopwatch->stop('dump');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collect(Request $request, Response $response, \Exception $exception = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serialize()
|
||||||
|
{
|
||||||
|
$ser = serialize($this->clonesRoot->data);
|
||||||
|
$this->clonesRoot->data = array();
|
||||||
|
$this->clonesRoot->isCollected = true;
|
||||||
|
|
||||||
|
return $ser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unserialize($data)
|
||||||
|
{
|
||||||
|
parent::unserialize($data);
|
||||||
|
|
||||||
|
$this->clonesRoot = $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDumpsCount()
|
||||||
|
{
|
||||||
|
return count($this->clonesRoot->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDumpsExcerpts()
|
||||||
|
{
|
||||||
|
$dumps = array();
|
||||||
|
|
||||||
|
foreach ($this->data as $dump) {
|
||||||
|
$data = $dump['data']->getRawData();
|
||||||
|
unset($dump['data']);
|
||||||
|
|
||||||
|
$data = $data[0][0];
|
||||||
|
|
||||||
|
if (isset($data->val)) {
|
||||||
|
$data = $data->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data->bin)) {
|
||||||
|
$data = 'b"'.$data->bin.'"';
|
||||||
|
} elseif (isset($data->str)) {
|
||||||
|
$data = '"'.$data->str.'"';
|
||||||
|
} elseif (isset($data->count)) {
|
||||||
|
$data = 'array('.$data->count.')';
|
||||||
|
} elseif (isset($data->class)) {
|
||||||
|
$data = $data->class.'{...}';
|
||||||
|
} elseif (isset($data->res)) {
|
||||||
|
$data = 'resource:'.$data->res.'{...}';
|
||||||
|
} elseif (is_array($data)) {
|
||||||
|
$data = 'array()';
|
||||||
|
} elseif (null === $data) {
|
||||||
|
$data = 'null';
|
||||||
|
} elseif (false === $data) {
|
||||||
|
$data = 'false';
|
||||||
|
} elseif (INF === $data) {
|
||||||
|
$data = 'INF';
|
||||||
|
} elseif (-INF === $data) {
|
||||||
|
$data = '-INF';
|
||||||
|
} elseif (NAN === $data) {
|
||||||
|
$data = 'NAN';
|
||||||
|
} elseif (true === $data) {
|
||||||
|
$data = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
$dump['dataExcerpt'] = $data;
|
||||||
|
$dumps[] = $dump;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dumps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDumps($getData = false)
|
||||||
|
{
|
||||||
|
if ($getData) {
|
||||||
|
$dumper = new JsonDumper();
|
||||||
|
}
|
||||||
|
$dumps = array();
|
||||||
|
|
||||||
|
foreach ($this->clonesRoot->data as $dump) {
|
||||||
|
$json = '';
|
||||||
|
if ($getData) {
|
||||||
|
$dumper->dump($dump['data'], function ($line) use (&$json) {$json .= $line;});
|
||||||
|
}
|
||||||
|
$dump['data'] = $json;
|
||||||
|
$dumps[] = $dump;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dumps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'dump';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flushDumps()
|
||||||
|
{
|
||||||
|
if (0 === $this->clonesRoot->clonesCount-- && !$this->clonesRoot->isCollected && $this->clonesRoot->data) {
|
||||||
|
$this->clonesRoot->clonesCount = 0;
|
||||||
|
$this->clonesRoot->isCollected = true;
|
||||||
|
|
||||||
|
$h = headers_list();
|
||||||
|
$i = count($h);
|
||||||
|
array_unshift($h, 'Content-Type: ' . ini_get('default_mimetype'));
|
||||||
|
while (0 !== stripos($h[$i], 'Content-Type:')) {
|
||||||
|
--$i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stripos($h[$i], 'html')) {
|
||||||
|
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
|
||||||
|
$dumper = new HtmlDumper();
|
||||||
|
} else {
|
||||||
|
$dumper = new CliDumper();
|
||||||
|
$dumper->setColors(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->clonesRoot->data as $i => $dump) {
|
||||||
|
$this->clonesRoot->data[$i] = null;
|
||||||
|
|
||||||
|
if ($dumper instanceof HtmlDumper) {
|
||||||
|
$dump['name'] = htmlspecialchars($dump['name'], ENT_QUOTES, 'UTF-8');
|
||||||
|
$dump['file'] = htmlspecialchars($dump['file'], ENT_QUOTES, 'UTF-8');
|
||||||
|
if ('' !== $dump['file']) {
|
||||||
|
$dump['name'] = "<abbr title=\"{$dump['file']}\">{$dump['name']}</abbr>";
|
||||||
|
}
|
||||||
|
echo "\n<br><span class=\"sf-dump-meta\">in {$dump['name']} on line {$dump['line']}:</span>";
|
||||||
|
} else {
|
||||||
|
echo "\nin {$dump['name']} on line {$dump['line']}:\n\n";
|
||||||
|
}
|
||||||
|
$dumper->dump($dump['data']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->clonesRoot->data = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpKernel\EventListener;
|
||||||
|
|
||||||
|
use Symfony\Component\Debug\Debug;
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
use Symfony\Component\HttpKernel\KernelEvents;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures dump() handler.
|
||||||
|
*
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
class DumpListener implements EventSubscriberInterface
|
||||||
|
{
|
||||||
|
private $container;
|
||||||
|
private $dumper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ContainerInterface $container Service container, for lazy loading.
|
||||||
|
* @param string $dumper var_dumper dumper service to use.
|
||||||
|
*/
|
||||||
|
public function __construct(ContainerInterface $container, $dumper)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
$this->dumper = $dumper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configure()
|
||||||
|
{
|
||||||
|
if ($this->container) {
|
||||||
|
$container = $this->container;
|
||||||
|
$dumper = $this->dumper;
|
||||||
|
$this->container = null;
|
||||||
|
|
||||||
|
Debug::setDumpHandler(function ($var) use ($container, $dumper) {
|
||||||
|
$dumper = $container->get($dumper);
|
||||||
|
$cloner = $container->get('var_dumper.cloner');
|
||||||
|
$handler = function ($var) use ($dumper, $cloner) {$dumper->dump($cloner->cloneVar($var));};
|
||||||
|
Debug::setDumpHandler($handler);
|
||||||
|
$handler($var);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSubscribedEvents()
|
||||||
|
{
|
||||||
|
// Register early to have a working dump() as early as possible
|
||||||
|
return array(KernelEvents::REQUEST => array('configure', 1024));
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ class HtmlDumper extends CliDumper
|
||||||
public static $defaultOutputStream = 'php://output';
|
public static $defaultOutputStream = 'php://output';
|
||||||
|
|
||||||
protected $dumpHeader;
|
protected $dumpHeader;
|
||||||
protected $dumpPrefix = '<pre class=sf-var-debug style=white-space:pre>';
|
protected $dumpPrefix = '<pre class=sf-dump style=white-space:pre>';
|
||||||
protected $dumpSuffix = '</pre>';
|
protected $dumpSuffix = '</pre>';
|
||||||
protected $colors = true;
|
protected $colors = true;
|
||||||
protected $headerIsDumped = false;
|
protected $headerIsDumped = false;
|
||||||
|
@ -88,7 +88,7 @@ class HtmlDumper extends CliDumper
|
||||||
$this->headerIsDumped = true;
|
$this->headerIsDumped = true;
|
||||||
$line = $this->line;
|
$line = $this->line;
|
||||||
|
|
||||||
$p = 'sf-var-debug';
|
$p = 'sf-dump';
|
||||||
$this->line = '<!DOCTYPE html><style>';
|
$this->line = '<!DOCTYPE html><style>';
|
||||||
parent::dumpLine(0);
|
parent::dumpLine(0);
|
||||||
$this->line .= "a.$p-ref {{$this->styles['ref']}}";
|
$this->line .= "a.$p-ref {{$this->styles['ref']}}";
|
||||||
|
@ -119,9 +119,9 @@ class HtmlDumper extends CliDumper
|
||||||
if ('ref' === $style) {
|
if ('ref' === $style) {
|
||||||
$ref = substr($val, 1);
|
$ref = substr($val, 1);
|
||||||
if ('#' === $val[0]) {
|
if ('#' === $val[0]) {
|
||||||
return "<a class=sf-var-debug-ref name=\"sf-var-debug-ref$ref\">$val</a>";
|
return "<a class=sf-dump-ref name=\"sf-dump-ref$ref\">$val</a>";
|
||||||
} else {
|
} else {
|
||||||
return "<a class=sf-var-debug-ref href=\"#sf-var-debug-ref$ref\">$val</a>";
|
return "<a class=sf-dump-ref href=\"#sf-dump-ref$ref\">$val</a>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,12 +131,12 @@ class HtmlDumper extends CliDumper
|
||||||
foreach (static::$controlChars as $c) {
|
foreach (static::$controlChars as $c) {
|
||||||
if (false !== strpos($val, $c)) {
|
if (false !== strpos($val, $c)) {
|
||||||
$r = "\x7F" === $c ? '?' : chr(64 + ord($c));
|
$r = "\x7F" === $c ? '?' : chr(64 + ord($c));
|
||||||
$val = str_replace($c, "<span class=sf-var-debug-cchr>$r</span>", $val);
|
$val = str_replace($c, "<span class=sf-dump-cchr>$r</span>", $val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "<span class=sf-var-debug-$style>$val</span>";
|
return "<span class=sf-dump-$style>$val</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,7 +150,7 @@ class HtmlDumper extends CliDumper
|
||||||
|
|
||||||
switch ($this->lastDepth - $depth) {
|
switch ($this->lastDepth - $depth) {
|
||||||
case +1: $this->line = '</span>'.$this->line; break;
|
case +1: $this->line = '</span>'.$this->line; break;
|
||||||
case -1: $this->line = "<span class=sf-var-debug-$depth>$this->line"; break;
|
case -1: $this->line = "<span class=sf-dump-$depth>$this->line"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 === $this->lastDepth) {
|
if (-1 === $this->lastDepth) {
|
||||||
|
|
|
@ -38,73 +38,73 @@ class HtmlDumperTest extends \PHPUnit_Framework_TestCase
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
<<<EOTXT
|
<<<EOTXT
|
||||||
<!DOCTYPE html><style>
|
<!DOCTYPE html><style>
|
||||||
a.sf-var-debug-ref {color:#444444}
|
a.sf-dump-ref {color:#444444}
|
||||||
span.sf-var-debug-num {font-weight:bold;color:#0087FF}
|
span.sf-dump-num {font-weight:bold;color:#0087FF}
|
||||||
span.sf-var-debug-const {font-weight:bold;color:#0087FF}
|
span.sf-dump-const {font-weight:bold;color:#0087FF}
|
||||||
span.sf-var-debug-str {font-weight:bold;color:#00D7FF}
|
span.sf-dump-str {font-weight:bold;color:#00D7FF}
|
||||||
span.sf-var-debug-cchr {font-style: italic}
|
span.sf-dump-cchr {font-style: italic}
|
||||||
span.sf-var-debug-note {color:#D7AF00}
|
span.sf-dump-note {color:#D7AF00}
|
||||||
span.sf-var-debug-ref {color:#444444}
|
span.sf-dump-ref {color:#444444}
|
||||||
span.sf-var-debug-public {color:#008700}
|
span.sf-dump-public {color:#008700}
|
||||||
span.sf-var-debug-protected {color:#D75F00}
|
span.sf-dump-protected {color:#D75F00}
|
||||||
span.sf-var-debug-private {color:#D70000}
|
span.sf-dump-private {color:#D70000}
|
||||||
span.sf-var-debug-meta {color:#005FFF}
|
span.sf-dump-meta {color:#005FFF}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<pre class=sf-var-debug style=white-space:pre><span class=sf-var-debug-0><span class=sf-var-debug-note>array:25</span> [
|
<pre class=sf-dump style=white-space:pre><span class=sf-dump-0><span class=sf-dump-note>array:25</span> [
|
||||||
<span class=sf-var-debug-1>"<span class=sf-var-debug-meta>number</span>" => <span class=sf-var-debug-const>1</span>
|
<span class=sf-dump-1>"<span class=sf-dump-meta>number</span>" => <span class=sf-dump-const>1</span>
|
||||||
<span class=sf-var-debug-meta>0</span> => <span class=sf-var-debug-const>null</span> <a class=sf-var-debug-ref name="sf-var-debug-ref1">#1</a>
|
<span class=sf-dump-meta>0</span> => <span class=sf-dump-const>null</span> <a class=sf-dump-ref name="sf-dump-ref1">#1</a>
|
||||||
"<span class=sf-var-debug-meta>const</span>" => <span class=sf-var-debug-num>1.1</span>
|
"<span class=sf-dump-meta>const</span>" => <span class=sf-dump-num>1.1</span>
|
||||||
<span class=sf-var-debug-meta>1</span> => <span class=sf-var-debug-const>true</span>
|
<span class=sf-dump-meta>1</span> => <span class=sf-dump-const>true</span>
|
||||||
<span class=sf-var-debug-meta>2</span> => <span class=sf-var-debug-const>false</span>
|
<span class=sf-dump-meta>2</span> => <span class=sf-dump-const>false</span>
|
||||||
<span class=sf-var-debug-meta>3</span> => <span class=sf-var-debug-num>NAN</span>
|
<span class=sf-dump-meta>3</span> => <span class=sf-dump-num>NAN</span>
|
||||||
<span class=sf-var-debug-meta>4</span> => <span class=sf-var-debug-num>INF</span>
|
<span class=sf-dump-meta>4</span> => <span class=sf-dump-num>INF</span>
|
||||||
<span class=sf-var-debug-meta>5</span> => <span class=sf-var-debug-num>-INF</span>
|
<span class=sf-dump-meta>5</span> => <span class=sf-dump-num>-INF</span>
|
||||||
<span class=sf-var-debug-meta>6</span> => <span class=sf-var-debug-const>9223372036854775807</span>
|
<span class=sf-dump-meta>6</span> => <span class=sf-dump-const>9223372036854775807</span>
|
||||||
"<span class=sf-var-debug-meta>str</span>" => "<span class=sf-var-debug-str>déjà</span>"
|
"<span class=sf-dump-meta>str</span>" => "<span class=sf-dump-str>déjà</span>"
|
||||||
<span class=sf-var-debug-meta>7</span> => b"<span class=sf-var-debug-str>é</span>"
|
<span class=sf-dump-meta>7</span> => b"<span class=sf-dump-str>é</span>"
|
||||||
"<span class=sf-var-debug-meta>[]</span>" => []
|
"<span class=sf-dump-meta>[]</span>" => []
|
||||||
"<span class=sf-var-debug-meta>res</span>" => resource:<span class=sf-var-debug-note>stream</span> {
|
"<span class=sf-dump-meta>res</span>" => resource:<span class=sf-dump-note>stream</span> {
|
||||||
<span class=sf-var-debug-2><span class=sf-var-debug-meta>wrapper_type</span>: "<span class=sf-var-debug-str>plainfile</span>"
|
<span class=sf-dump-2><span class=sf-dump-meta>wrapper_type</span>: "<span class=sf-dump-str>plainfile</span>"
|
||||||
<span class=sf-var-debug-meta>stream_type</span>: "<span class=sf-var-debug-str>dir</span>"
|
<span class=sf-dump-meta>stream_type</span>: "<span class=sf-dump-str>dir</span>"
|
||||||
<span class=sf-var-debug-meta>mode</span>: "<span class=sf-var-debug-str>r</span>"
|
<span class=sf-dump-meta>mode</span>: "<span class=sf-dump-str>r</span>"
|
||||||
<span class=sf-var-debug-meta>unread_bytes</span>: <span class=sf-var-debug-const>0</span>
|
<span class=sf-dump-meta>unread_bytes</span>: <span class=sf-dump-const>0</span>
|
||||||
<span class=sf-var-debug-meta>seekable</span>: <span class=sf-var-debug-const>true</span>
|
<span class=sf-dump-meta>seekable</span>: <span class=sf-dump-const>true</span>
|
||||||
<span class=sf-var-debug-meta>timed_out</span>: <span class=sf-var-debug-const>false</span>
|
<span class=sf-dump-meta>timed_out</span>: <span class=sf-dump-const>false</span>
|
||||||
<span class=sf-var-debug-meta>blocked</span>: <span class=sf-var-debug-const>true</span>
|
<span class=sf-dump-meta>blocked</span>: <span class=sf-dump-const>true</span>
|
||||||
<span class=sf-var-debug-meta>eof</span>: <span class=sf-var-debug-const>false</span>
|
<span class=sf-dump-meta>eof</span>: <span class=sf-dump-const>false</span>
|
||||||
<span class=sf-var-debug-meta>options</span>: []
|
<span class=sf-dump-meta>options</span>: []
|
||||||
</span>}
|
</span>}
|
||||||
<span class=sf-var-debug-meta>8</span> => resource:<span class=sf-var-debug-note>Unknown</span> {}
|
<span class=sf-dump-meta>8</span> => resource:<span class=sf-dump-note>Unknown</span> {}
|
||||||
"<span class=sf-var-debug-meta>obj</span>" => <span class=sf-var-debug-note>Symfony\Component\VarDumper\Tests\Fixture\DumbFoo</span> { <a class=sf-var-debug-ref name="sf-var-debug-ref2">#2</a>
|
"<span class=sf-dump-meta>obj</span>" => <span class=sf-dump-note>Symfony\Component\VarDumper\Tests\Fixture\DumbFoo</span> { <a class=sf-dump-ref name="sf-dump-ref2">#2</a>
|
||||||
<span class=sf-var-debug-2><span class=sf-var-debug-public>foo</span>: "<span class=sf-var-debug-str>foo</span>"
|
<span class=sf-dump-2><span class=sf-dump-public>foo</span>: "<span class=sf-dump-str>foo</span>"
|
||||||
"<span class=sf-var-debug-public>bar</span>": "<span class=sf-var-debug-str>bar</span>"
|
"<span class=sf-dump-public>bar</span>": "<span class=sf-dump-str>bar</span>"
|
||||||
</span>}
|
</span>}
|
||||||
"<span class=sf-var-debug-meta>closure</span>" => <span class=sf-var-debug-note>Closure</span> {
|
"<span class=sf-dump-meta>closure</span>" => <span class=sf-dump-note>Closure</span> {
|
||||||
<span class=sf-var-debug-2><span class=sf-var-debug-meta>reflection</span>: """
|
<span class=sf-dump-2><span class=sf-dump-meta>reflection</span>: """
|
||||||
<span class=sf-var-debug-str>Closure [ <user> {$closureLabel} Symfony\Component\VarDumper\Tests\Fixture\{closure} ] {</span>
|
<span class=sf-dump-str>Closure [ <user> {$closureLabel} Symfony\Component\VarDumper\Tests\Fixture\{closure} ] {</span>
|
||||||
<span class=sf-var-debug-str> @@ {$var['file']} {$var['line']} - {$var['line']}</span>
|
<span class=sf-dump-str> @@ {$var['file']} {$var['line']} - {$var['line']}</span>
|
||||||
|
|
||||||
<span class=sf-var-debug-str> - Parameters [2] {</span>
|
<span class=sf-dump-str> - Parameters [2] {</span>
|
||||||
<span class=sf-var-debug-str> Parameter #0 [ <required> \$a ]</span>
|
<span class=sf-dump-str> Parameter #0 [ <required> \$a ]</span>
|
||||||
<span class=sf-var-debug-str> Parameter #1 [ <optional> PDO or NULL &\$b = NULL ]</span>
|
<span class=sf-dump-str> Parameter #1 [ <optional> PDO or NULL &\$b = NULL ]</span>
|
||||||
<span class=sf-var-debug-str> }</span>
|
<span class=sf-dump-str> }</span>
|
||||||
<span class=sf-var-debug-str>}</span>
|
<span class=sf-dump-str>}</span>
|
||||||
"""
|
"""
|
||||||
</span>}
|
</span>}
|
||||||
"<span class=sf-var-debug-meta>line</span>" => <span class=sf-var-debug-const>{$var['line']}</span>
|
"<span class=sf-dump-meta>line</span>" => <span class=sf-dump-const>{$var['line']}</span>
|
||||||
"<span class=sf-var-debug-meta>nobj</span>" => <span class=sf-var-debug-note>array:1</span> [
|
"<span class=sf-dump-meta>nobj</span>" => <span class=sf-dump-note>array:1</span> [
|
||||||
<span class=sf-var-debug-2><span class=sf-var-debug-meta>0</span> => {} <a class=sf-var-debug-ref name="sf-var-debug-ref3">#3</a>
|
<span class=sf-dump-2><span class=sf-dump-meta>0</span> => {} <a class=sf-dump-ref name="sf-dump-ref3">#3</a>
|
||||||
</span>]
|
</span>]
|
||||||
"<span class=sf-var-debug-meta>recurs</span>" => <span class=sf-var-debug-note>array:1</span> [ <a class=sf-var-debug-ref name="sf-var-debug-ref4">#4</a>
|
"<span class=sf-dump-meta>recurs</span>" => <span class=sf-dump-note>array:1</span> [ <a class=sf-dump-ref name="sf-dump-ref4">#4</a>
|
||||||
<span class=sf-var-debug-2><span class=sf-var-debug-meta>0</span> => <span class=sf-var-debug-note>array:1</span> [<a class=sf-var-debug-ref href="#sf-var-debug-ref4">&4</a>]
|
<span class=sf-dump-2><span class=sf-dump-meta>0</span> => <span class=sf-dump-note>array:1</span> [<a class=sf-dump-ref href="#sf-dump-ref4">&4</a>]
|
||||||
</span>]
|
</span>]
|
||||||
<span class=sf-var-debug-meta>9</span> => <span class=sf-var-debug-const>null</span> <a class=sf-var-debug-ref href="#sf-var-debug-ref1">&1</a>
|
<span class=sf-dump-meta>9</span> => <span class=sf-dump-const>null</span> <a class=sf-dump-ref href="#sf-dump-ref1">&1</a>
|
||||||
"<span class=sf-var-debug-meta>sobj</span>" => <span class=sf-var-debug-note>Symfony\Component\VarDumper\Tests\Fixture\DumbFoo</span> {<a class=sf-var-debug-ref href="#sf-var-debug-ref2">@2</a>}
|
"<span class=sf-dump-meta>sobj</span>" => <span class=sf-dump-note>Symfony\Component\VarDumper\Tests\Fixture\DumbFoo</span> {<a class=sf-dump-ref href="#sf-dump-ref2">@2</a>}
|
||||||
"<span class=sf-var-debug-meta>snobj</span>" => {<a class=sf-var-debug-ref href="#sf-var-debug-ref3">&3</a>}
|
"<span class=sf-dump-meta>snobj</span>" => {<a class=sf-dump-ref href="#sf-dump-ref3">&3</a>}
|
||||||
"<span class=sf-var-debug-meta>snobj2</span>" => {<a class=sf-var-debug-ref href="#sf-var-debug-ref3">@3</a>}
|
"<span class=sf-dump-meta>snobj2</span>" => {<a class=sf-dump-ref href="#sf-dump-ref3">@3</a>}
|
||||||
"<span class=sf-var-debug-meta>file</span>" => "<span class=sf-var-debug-str>{$var['file']}</span>"
|
"<span class=sf-dump-meta>file</span>" => "<span class=sf-dump-str>{$var['file']}</span>"
|
||||||
b"<span class=sf-var-debug-meta>bin-key-é</span>" => ""
|
b"<span class=sf-dump-meta>bin-key-é</span>" => ""
|
||||||
</span>]
|
</span>]
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
Reference in New Issue