diff --git a/composer.json b/composer.json index 07e4ee4254..0a14b8ff74 100644 --- a/composer.json +++ b/composer.json @@ -87,7 +87,7 @@ ], "files": [ "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", diff --git a/src/Symfony/Bridge/Twig/Extension/DumpExtension.php b/src/Symfony/Bridge/Twig/Extension/DumpExtension.php new file mode 100644 index 0000000000..a0e895dd87 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Extension/DumpExtension.php @@ -0,0 +1,32 @@ + + * + * 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
+ */
+class DumpExtension extends \Twig_Extension
+{
+ public function getTokenParsers()
+ {
+ return array(new DumpTokenParser());
+ }
+
+ public function getName()
+ {
+ return 'dump';
+ }
+}
diff --git a/src/Symfony/Bridge/Twig/Node/DumpNode.php b/src/Symfony/Bridge/Twig/Node/DumpNode.php
new file mode 100644
index 0000000000..ca64660243
--- /dev/null
+++ b/src/Symfony/Bridge/Twig/Node/DumpNode.php
@@ -0,0 +1,89 @@
+
+ *
+ * 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
+ */
+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[] = '
+ */
+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));
+ }
+}
diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
index 3182dc4cb1..e333eb8539 100644
--- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
+++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
@@ -21,7 +21,7 @@ class HtmlDumper extends CliDumper
public static $defaultOutputStream = 'php://output';
protected $dumpHeader;
- protected $dumpPrefix = '
+ * {% dump %}
+ * {% dump foo %}
+ * {% dump foo, bar %}
+ *
+ *
+ * @author Julien Galenski '.htmlspecialchars($src[$i - 1]).'
'.implode("\n", $fileExcerpt).'
';
+ }
+ 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 '';
+ $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'] = "{$dump['name']}";
+ }
+ echo "\n
";
+ } else {
+ echo "\nin {$dump['name']} on line {$dump['line']}:\n\n";
+ }
+ $dumper->dump($dump['data']);
+ }
+
+ $this->clonesRoot->data = array();
+ }
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/EventListener/DumpListener.php b/src/Symfony/Component/HttpKernel/EventListener/DumpListener.php
new file mode 100644
index 0000000000..89dee034b5
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/EventListener/DumpListener.php
@@ -0,0 +1,61 @@
+
+ *
+ * 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 ';
+ protected $dumpPrefix = '
';
protected $dumpSuffix = '
';
protected $colors = true;
protected $headerIsDumped = false;
@@ -88,7 +88,7 @@ class HtmlDumper extends CliDumper
$this->headerIsDumped = true;
$line = $this->line;
- $p = 'sf-var-debug';
+ $p = 'sf-dump';
$this->line = '
-array:25 [
- "1
- => null #1
- " " => 1.1
- => true
- => false
- => NAN
- => INF
- => -INF
- => 9223372036854775807
- " " => "déjà"
- => b"é"
- " " => []
- " " => resource:stream {
- plainfile"
- : "dir"
- : "r"
- : 0
- : true
- : false
- : true
- : false
- : []
+
array:25 [
+ "1
+ => null #1
+ " " => 1.1
+ => true
+ => false
+ => NAN
+ => INF
+ => -INF
+ => 9223372036854775807
+ " " => "déjà"
+ => b"é"
+ " " => []
+ " " => resource:stream {
+ plainfile"
+ : "dir"
+ : "r"
+ : 0
+ : true
+ : false
+ : true
+ : false
+ : []
}
- : " => resource:Unknown {}
- " " => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo { #2
- foo: "foo"
- "bar": "bar"
+ => resource:Unknown {}
+ " " => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo { #2
+ foo: "foo"
+ "bar": "bar"
}
- " " => Closure {
- Closure [ <user> {$closureLabel} Symfony\Component\VarDumper\Tests\Fixture\{closure} ] {
- @@ {$var['file']} {$var['line']} - {$var['line']}
+ " " => Closure {
+ Closure [ <user> {$closureLabel} Symfony\Component\VarDumper\Tests\Fixture\{closure} ] {
+ @@ {$var['file']} {$var['line']} - {$var['line']}
- - Parameters [2] {
- Parameter #0 [ <required> \$a ]
- Parameter #1 [ <optional> PDO or NULL &\$b = NULL ]
- }
- }
+ - Parameters [2] {
+ Parameter #0 [ <required> \$a ]
+ Parameter #1 [ <optional> PDO or NULL &\$b = NULL ]
+ }
+ }
"""
}
- " : """
+ " => {$var['line']}
- " " => array:1 [
- #3
+ " " => {$var['line']}
+ " " => array:1 [
+ #3
]
- " => {} " => array:1 [ #4
- array:1 [&4]
+ " " => array:1 [ #4
+ array:1 [&4]
]
- => => null &1
- " " => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {@2}
- " " => {&3}
- " " => {@3}
- " " => "{$var['file']}"
- b" " => ""
+ => null &1
+ " " => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {@2}
+ " " => {&3}
+ " " => {@3}
+ " " => "{$var['file']}"
+ b" " => ""
]
=> => {} : """
- " =>
: " " =>