feature #19672 [VarDumper] Allow dumping subparts of cloned Data structures (nicolas-grekas)

This PR was merged into the 3.2-dev branch.

Discussion
----------

[VarDumper] Allow dumping subparts of cloned Data structures

| Q             | A
| ------------- | ---
| Branch?       | master
| New feature?  | yes
| Tests pass?   | yes
| License       | MIT
| Doc PR     | https://github.com/symfony/symfony-docs/pull/6891

ping @wouterj: with this, we'll be able to dump only the trace for deprecations in #19614 instead of being forced to dump the full exception right now. See test case.
We'd do `{{ profiler_dump(log.context.seek('trace')) }}` in `logger.html.twig`.

Commits
-------

8f2f440 [VarDumper] Allow dumping subparts of cloned Data structures
This commit is contained in:
Fabien Potencier 2016-08-19 09:43:43 -07:00
commit 640c6208ef
4 changed files with 91 additions and 4 deletions

View File

@ -11,12 +11,16 @@
namespace Symfony\Component\VarDumper\Cloner;
use Symfony\Component\VarDumper\Caster\Caster;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class Data
{
private $data;
private $position = 0;
private $key = 0;
private $maxDepth = 20;
private $maxItemsPerDepth = -1;
private $useRefHandles = -1;
@ -82,13 +86,57 @@ class Data
return $data;
}
/**
* Seeks to a specific key in nested data structures.
*
* @param string|int $key The key to seek to
*
* @return self|null A clone of $this of null if the key is not set
*/
public function seek($key)
{
$item = $this->data[$this->position][$this->key];
if (!$item instanceof Stub || !$item->position) {
return;
}
$keys = array($key);
switch ($item->type) {
case Stub::TYPE_OBJECT:
$keys[] = Caster::PREFIX_DYNAMIC.$key;
$keys[] = Caster::PREFIX_PROTECTED.$key;
$keys[] = Caster::PREFIX_VIRTUAL.$key;
$keys[] = "\0$item->class\0$key";
case Stub::TYPE_ARRAY:
case Stub::TYPE_RESOURCE:
break;
default:
return;
}
$data = null;
$children = $this->data[$item->position];
foreach ($keys as $key) {
if (isset($children[$key]) || array_key_exists($key, $children)) {
$data = clone $this;
$data->key = $key;
$data->position = $item->position;
break;
}
}
return $data;
}
/**
* Dumps data with a DumperInterface dumper.
*/
public function dump(DumperInterface $dumper)
{
$refs = array(0);
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[0][0]);
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]);
}
/**

View File

@ -29,7 +29,7 @@ trait VarDumperTestTrait
$this->assertStringMatchesFormat(rtrim($dump), $this->getDump($data), $message);
}
protected function getDump($data)
protected function getDump($data, $key = null)
{
$flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0;
$flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0;
@ -39,7 +39,11 @@ trait VarDumperTestTrait
$cloner->setMaxItems(-1);
$dumper = new CliDumper($h, null, $flags);
$dumper->setColors(false);
$dumper->dump($cloner->cloneVar($data)->withRefHandles(false));
$data = $cloner->cloneVar($data)->withRefHandles(false);
if (null !== $key && null === $data = $data->seek($key)) {
return;
}
$dumper->dump($data);
$data = stream_get_contents($h, -1, 0);
fclose($h);

View File

@ -59,6 +59,31 @@ EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $e);
}
public function testSeek()
{
$e = $this->getTestException(2);
$expectedDump = <<<'EODUMP'
{
%d. %sExceptionCasterTest.php:23: {
22: {
23: return new \Exception('foo');
24: }
}
%d. %sExceptionCasterTest.php:%d: {
%d: {
%d: $e = $this->getTestException(2);
%d:
args: {
2
}
}
%A
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $this->getDump($e, 'trace'));
}
public function testNoArgs()
{
$e = $this->getTestException(1);

View File

@ -52,6 +52,8 @@ Symfony\Component\VarDumper\Cloner\Data Object
)
[position:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[key:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
@ -126,6 +128,8 @@ Symfony\Component\VarDumper\Cloner\Data Object
)
[position:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[key:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
@ -143,7 +147,7 @@ EOTXT;
$clone = $cloner->cloneVar($data);
$expected = <<<'EOTXT'
object(Symfony\Component\VarDumper\Cloner\Data)#%i (4) {
object(Symfony\Component\VarDumper\Cloner\Data)#%i (6) {
["data":"Symfony\Component\VarDumper\Cloner\Data":private]=>
array(2) {
[0]=>
@ -187,6 +191,10 @@ object(Symfony\Component\VarDumper\Cloner\Data)#%i (4) {
}
}
}
["position":"Symfony\Component\VarDumper\Cloner\Data":private]=>
int(0)
["key":"Symfony\Component\VarDumper\Cloner\Data":private]=>
int(0)
["maxDepth":"Symfony\Component\VarDumper\Cloner\Data":private]=>
int(20)
["maxItemsPerDepth":"Symfony\Component\VarDumper\Cloner\Data":private]=>
@ -242,6 +250,8 @@ Symfony\Component\VarDumper\Cloner\Data Object
)
[position:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[key:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1