Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[VarDumper] Fix dumping by splitting Server/Connection out of Dumper/ServerDumper #27614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\VarDumper\Dumper\ServerDumper;

/**
* DebugExtension.
Expand All @@ -43,20 +42,21 @@ public function load(array $configs, ContainerBuilder $container)
->addMethodCall('setMaxString', array($config['max_string_length']));

if (null === $config['dump_destination']) {
//no-op
$container->getDefinition('var_dumper.command.server_dump')
->setClass(ServerDumpPlaceholderCommand::class)
;
} elseif (0 === strpos($config['dump_destination'], 'tcp://')) {
$serverDumperHost = $config['dump_destination'];
$container->getDefinition('debug.dump_listener')
->replaceArgument(1, new Reference('var_dumper.server_dumper'))
->replaceArgument(2, new Reference('var_dumper.server_connection'))
;
$container->getDefinition('data_collector.dump')
->replaceArgument(4, new Reference('var_dumper.server_dumper'))
->replaceArgument(4, new Reference('var_dumper.server_connection'))
;
$container->getDefinition('var_dumper.dump_server')
->replaceArgument(0, $serverDumperHost)
->replaceArgument(0, $config['dump_destination'])
;
$container->getDefinition('var_dumper.server_dumper')
->replaceArgument(0, $serverDumperHost)
$container->getDefinition('var_dumper.server_connection')
->replaceArgument(0, $config['dump_destination'])
;
} else {
$container->getDefinition('var_dumper.cli_dumper')
Expand All @@ -65,13 +65,9 @@ public function load(array $configs, ContainerBuilder $container)
$container->getDefinition('data_collector.dump')
->replaceArgument(4, new Reference('var_dumper.cli_dumper'))
;
}

if (!isset($serverDumperHost)) {
$container->getDefinition('var_dumper.command.server_dump')->setClass(ServerDumpPlaceholderCommand::class);
if (!class_exists(ServerDumper::class)) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check is not needed since VarDumper is a mandatory requirement of DebugBundle

$container->removeDefinition('var_dumper.command.server_dump');
}
$container->getDefinition('var_dumper.command.server_dump')
->setClass(ServerDumpPlaceholderCommand::class)
;
}
}

Expand Down
8 changes: 4 additions & 4 deletions 8 src/Symfony/Bundle/DebugBundle/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@
<argument type="service" id="debug.file_link_formatter" on-invalid="ignore"></argument>
<argument>%kernel.charset%</argument>
<argument type="service" id="request_stack" />
<argument>null</argument><!-- var_dumper.cli_dumper or var_dumper.server_dumper when debug.dump_destination is set -->
<argument>null</argument><!-- var_dumper.cli_dumper or var_dumper.server_connection when debug.dump_destination is set -->
</service>

<service id="debug.dump_listener" class="Symfony\Component\HttpKernel\EventListener\DumpListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="var_dumper.cloner" />
<argument type="service" id="var_dumper.cli_dumper" />
<argument>null</argument>
</service>

<service id="var_dumper.cloner" class="Symfony\Component\VarDumper\Cloner\VarCloner" public="true" />
Expand All @@ -50,9 +51,8 @@
</call>
</service>

<service id="var_dumper.server_dumper" class="Symfony\Component\VarDumper\Dumper\ServerDumper">
<argument>null</argument> <!-- server host -->
<argument type="service" id="var_dumper.cli_dumper" />
<service id="var_dumper.server_connection" class="Symfony\Component\VarDumper\Server\Connection">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be hidden ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, we hide only services with "random" names, not sure this PR should be the one changing this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's true. I'm quite sure I reviewed some PRs hiding some service names. But I'm still fine if the main rule is to hide only "random" names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find any with a quick grep, let's let it as is.

<argument /> <!-- server host -->
<argument type="collection">
<argument type="service" key="source">
<service class="Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider">
Expand Down
2 changes: 1 addition & 1 deletion 2 src/Symfony/Bundle/DebugBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"ext-xml": "*",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/twig-bridge": "~3.4|~4.0",
"symfony/var-dumper": "~4.1"
"symfony/var-dumper": "^4.1.1"
},
"require-dev": {
"symfony/config": "~3.4|~4.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
use Symfony\Component\VarDumper\Dumper\ServerDumper;
use Symfony\Component\VarDumper\Server\Connection;

/**
* @author Nicolas Grekas <p@tchwork.com>
Expand All @@ -38,17 +38,18 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
private $charset;
private $requestStack;
private $dumper;
private $dumperIsInjected;
private $sourceContextProvider;

public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, DataDumperInterface $dumper = null)
/**
* @param DataDumperInterface|Connection|null $dumper
*/
public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, $dumper = null)
{
$this->stopwatch = $stopwatch;
$this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->charset = $charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8';
$this->requestStack = $requestStack;
$this->dumper = $dumper;
$this->dumperIsInjected = null !== $dumper;

// All clones share these properties by reference:
$this->rootRefs = array(
Expand All @@ -58,7 +59,7 @@ public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null,
&$this->clonesCount,
);

$this->sourceContextProvider = $dumper instanceof ServerDumper && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset);
$this->sourceContextProvider = $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset);
}

public function __clone()
Expand All @@ -71,14 +72,17 @@ public function dump(Data $data)
if ($this->stopwatch) {
$this->stopwatch->start('dump');
}
if ($this->isCollected && !$this->dumper) {
$this->isCollected = false;
}

list('name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt) = $this->sourceContextProvider->getContext();

if ($this->dumper) {
if ($this->dumper instanceof Connection) {
if (!$this->dumper->write($data)) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the root of the issue: not being able to know if we wrote anything to the server to set $this->isCollected correctly

$this->isCollected = false;
}
} elseif ($this->dumper) {
$this->doDump($this->dumper, $data, $name, $file, $line);
} else {
$this->isCollected = false;
}

$this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt');
Expand Down Expand Up @@ -141,9 +145,6 @@ public function serialize()
$this->data = array();
$this->dataCount = 0;
$this->isCollected = true;
if (!$this->dumperIsInjected) {
$this->dumper = null;
}

return $ser;
}
Expand Down Expand Up @@ -245,7 +246,7 @@ private function doDump(DataDumperInterface $dumper, $data, $name, $file, $line)
};
$contextDumper = $contextDumper->bindTo($dumper, $dumper);
$contextDumper($name, $file, $line, $this->fileLinkFormat);
} elseif (!$dumper instanceof ServerDumper) {
} else {
$cloner = new VarCloner();
$dumper->dump($cloner->cloneVar($name.' on line '.$line.':'));
}
Expand Down
14 changes: 11 additions & 3 deletions 14 src/Symfony/Component/HttpKernel/EventListener/DumpListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
use Symfony\Component\VarDumper\Server\Connection;
use Symfony\Component\VarDumper\VarDumper;

/**
Expand All @@ -26,20 +27,27 @@ class DumpListener implements EventSubscriberInterface
{
private $cloner;
private $dumper;
private $connection;

public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper)
public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper, Connection $connection = null)
{
$this->cloner = $cloner;
$this->dumper = $dumper;
$this->connection = $connection;
}

public function configure()
{
$cloner = $this->cloner;
$dumper = $this->dumper;
$connection = $this->connection;

VarDumper::setHandler(function ($var) use ($cloner, $dumper) {
$dumper->dump($cloner->cloneVar($var));
VarDumper::setHandler(static function ($var) use ($cloner, $dumper, $connection) {
$data = $cloner->cloneVar($var);

if (!$connection || !$connection->write($data)) {
$dumper->dump($data);
}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\ServerDumper;
use Symfony\Component\VarDumper\Server\Connection;

/**
* @author Nicolas Grekas <p@tchwork.com>
Expand Down Expand Up @@ -57,13 +57,13 @@ public function testDump()
$this->assertSame('a:2:{i:0;b:0;i:1;s:5:"UTF-8";}', $collector->serialize());
}

public function testDumpWithServerDumper()
public function testDumpWithServerConnection()
{
$data = new Data(array(array(123)));

// Server is up, server dumper is used
$serverDumper = $this->getMockBuilder(ServerDumper::class)->disableOriginalConstructor()->getMock();
$serverDumper->expects($this->once())->method('dump');
$serverDumper = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
$serverDumper->expects($this->once())->method('write')->willReturn(true);

$collector = new DumpDataCollector(null, null, null, null, $serverDumper);
$collector->dump($data);
Expand Down
4 changes: 2 additions & 2 deletions 4 src/Symfony/Component/HttpKernel/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"symfony/stopwatch": "~3.4|~4.0",
"symfony/templating": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/var-dumper": "~4.1",
"symfony/var-dumper": "^4.1.1",
"psr/cache": "~1.0"
},
"provide": {
Expand All @@ -46,7 +46,7 @@
"conflict": {
"symfony/config": "<3.4",
"symfony/dependency-injection": "<4.1",
"symfony/var-dumper": "<4.1",
"symfony/var-dumper": "<4.1.1",
"twig/twig": "<1.34|<2.4,>=2"
},
"suggest": {
Expand Down
2 changes: 1 addition & 1 deletion 2 src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public function dump(Data $data, $output = null)
*/
protected function dumpLine($depth)
{
call_user_func($this->lineDumper, $this->line, $depth, $this->indentPad);
\call_user_func($this->lineDumper, $this->line, $depth, $this->indentPad);
$this->line = '';
}

Expand Down
76 changes: 7 additions & 69 deletions 76 src/Symfony/Component/VarDumper/Dumper/ServerDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
use Symfony\Component\VarDumper\Server\Connection;

/**
* ServerDumper forwards serialized Data clones to a server.
Expand All @@ -21,10 +22,8 @@
*/
class ServerDumper implements DataDumperInterface
{
private $host;
private $connection;
private $wrappedDumper;
private $contextProviders;
private $socket;

/**
* @param string $host The server host
Expand All @@ -33,83 +32,22 @@ class ServerDumper implements DataDumperInterface
*/
public function __construct(string $host, DataDumperInterface $wrappedDumper = null, array $contextProviders = array())
{
if (false === strpos($host, '://')) {
$host = 'tcp://'.$host;
}

$this->host = $host;
$this->connection = new Connection($host, $contextProviders);
$this->wrappedDumper = $wrappedDumper;
$this->contextProviders = $contextProviders;
}

public function getContextProviders(): array
{
return $this->contextProviders;
return $this->connection->getContextProviders();
}

/**
* {@inheritdoc}
*/
public function dump(Data $data, $output = null): void
{
set_error_handler(array(self::class, 'nullErrorHandler'));

$failed = false;
try {
if (!$this->socket = $this->socket ?: $this->createSocket()) {
$failed = true;

return;
}
} finally {
restore_error_handler();
if ($failed && $this->wrappedDumper) {
$this->wrappedDumper->dump($data);
}
}

set_error_handler(array(self::class, 'nullErrorHandler'));

$context = array('timestamp' => time());
foreach ($this->contextProviders as $name => $provider) {
$context[$name] = $provider->getContext();
}
$context = array_filter($context);

$encodedPayload = base64_encode(serialize(array($data, $context)))."\n";
$failed = false;

try {
$retry = 3;
while ($retry > 0 && $failed = (-1 === stream_socket_sendto($this->socket, $encodedPayload))) {
stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
if ($failed = !$this->socket = $this->createSocket()) {
break;
}

--$retry;
}
} finally {
restore_error_handler();
if ($failed && $this->wrappedDumper) {
$this->wrappedDumper->dump($data);
}
}
}

private static function nullErrorHandler()
public function dump(Data $data)
{
// noop
}

private function createSocket()
{
$socket = stream_socket_client($this->host, $errno, $errstr, 1, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT);

if ($socket) {
stream_set_blocking($socket, false);
if (!$this->connection->write($data) && $this->wrappedDumper) {
$this->wrappedDumper->dump($data);
}

return $socket;
}
}
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.