feature #28898 [Console] Add dumper (ro0NL)

This PR was squashed before being merged into the 4.3-dev branch (closes #28898).

Discussion
----------

[Console] Add dumper

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | #...   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | https://github.com/symfony/symfony-docs/issues/10502

This PR adds a new `Dumper` helper in the Console component. As there are 2 types of dumps

- debug purpose (e.g. `dd()`, `dump()`)
- output purpose (see #24208, #27684)

For the latter we cannot use the global system (debug) dumper, i.e. `VarDumper::dump()`, we need something tied to the current output and dependency free. Here it is:

```php
$io = new SymfonyStyle($input, $output);
$dumper = new Dumper($io);

$io->writeln($dumper([-0.5, 0, 1]));
$io->writeln($dumper(new \stdClass()));
$io->writeln($dumper(123));
$io->writeln($dumper('foo'));
$io->writeln($dumper(null));
$io->writeln($dumper(true));
```

With VarDumper comonent:

![image](https://user-images.githubusercontent.com/1047696/47069483-4cc26f80-d1ef-11e8-902e-2f9b0f040f25.png)

Without:

![image](https://user-images.githubusercontent.com/1047696/47069517-6663b700-d1ef-11e8-9328-ae1db0b83d7e.png)

> https://github.com/symfony/symfony/pull/27684#discussion_r224054237 var-dumper is not a mandatory dep of fwb, can we do without?

Now we can  :)

Commits
-------

fc7465c02c [Console] Add dumper
This commit is contained in:
Fabien Potencier 2019-03-24 11:32:40 +01:00
commit c52af28b0e
5 changed files with 182 additions and 0 deletions

View File

@ -0,0 +1,64 @@
<?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\Console\Helper;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
/**
* @author Roland Franssen <franssen.roland@gmail.com>
*/
final class Dumper
{
private $output;
private $dumper;
private $cloner;
private $handler;
public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null)
{
$this->output = $output;
$this->dumper = $dumper;
$this->cloner = $cloner;
if (class_exists(CliDumper::class)) {
$this->handler = function ($var): string {
$dumper = $this->dumper ?? $this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
$dumper->setColors($this->output->isDecorated());
return rtrim($dumper->dump(($this->cloner ?? $this->cloner = new VarCloner())->cloneVar($var)->withRefHandles(false), true));
};
} else {
$this->handler = function ($var): string {
switch (true) {
case null === $var:
return 'null';
case true === $var:
return 'true';
case false === $var:
return 'false';
case \is_string($var):
return '"'.$var.'"';
default:
return rtrim(print_r($var, true));
}
};
}
}
public function __invoke($var): string
{
return ($this->handler)($var);
}
}

View File

@ -0,0 +1,58 @@
<?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\Console\Tests\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ClassExistsMock;
use Symfony\Component\Console\Helper\Dumper;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\VarDumper\Dumper\CliDumper;
class DumperNativeFallbackTest extends TestCase
{
public static function setUpBeforeClass()
{
ClassExistsMock::register(Dumper::class);
ClassExistsMock::withMockedClasses([
CliDumper::class => false,
]);
}
public static function tearDownAfterClass()
{
ClassExistsMock::withMockedClasses([]);
}
/**
* @dataProvider provideVariables
*/
public function testInvoke($variable, $primitiveString)
{
$dumper = new Dumper($this->getMockBuilder(OutputInterface::class)->getMock());
$this->assertSame($primitiveString, $dumper($variable));
}
public function provideVariables()
{
return [
[null, 'null'],
[true, 'true'],
[false, 'false'],
[1, '1'],
[-1.5, '-1.5'],
['string', '"string"'],
[[1, '2'], "Array\n(\n [0] => 1\n [1] => 2\n)"],
[new \stdClass(), "stdClass Object\n(\n)"],
];
}
}

View File

@ -0,0 +1,58 @@
<?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\Console\Tests\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\Dumper;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
class DumperTest extends TestCase
{
use VarDumperTestTrait;
public static function setUpBeforeClass()
{
putenv('DUMP_LIGHT_ARRAY=1');
putenv('DUMP_COMMA_SEPARATOR=1');
}
public static function tearDownAfterClass()
{
putenv('DUMP_LIGHT_ARRAY');
putenv('DUMP_COMMA_SEPARATOR');
}
/**
* @dataProvider provideVariables
*/
public function testInvoke($variable)
{
$dumper = new Dumper($this->getMockBuilder(OutputInterface::class)->getMock());
$this->assertDumpMatchesFormat($dumper($variable), $variable);
}
public function provideVariables()
{
return [
[null],
[true],
[false],
[1],
[-1.5],
['string'],
[[1, '2']],
[new \stdClass()],
];
}
}

View File

@ -27,6 +27,7 @@
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/lock": "~3.4|~4.0",
"symfony/process": "~3.4|~4.0",
"symfony/var-dumper": "^4.3",
"psr/log": "~1.0"
},
"provide": {

View File

@ -33,6 +33,7 @@ trait VarDumperTestTrait
{
$flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0;
$flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0;
$flags |= getenv('DUMP_COMMA_SEPARATOR') ? CliDumper::DUMP_COMMA_SEPARATOR : 0;
$cloner = new VarCloner();
$cloner->setMaxItems(-1);