@@ -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( @@ -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() @@ -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)) { + $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'); @@ -141,9 +145,6 @@ public function serialize() $this->data = array(); $this->dataCount = 0; $this->isCollected = true; - if (!$this->dumperIsInjected) { - $this->dumper = null; - } return $ser; } @@ -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.':')); } diff --git a/src/Symfony/Component/HttpKernel/EventListener/DumpListener.php b/src/Symfony/Component/HttpKernel/EventListener/DumpListener.php index de19e13113e59..3acbe7d46c867 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/DumpListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/DumpListener.php @@ -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; /** @@ -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); + } }); } diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php index adfb3567c6777..57384a79ffe92 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php @@ -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
@@ -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);
diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json
index e610f27418777..453561f62d086 100644
--- a/src/Symfony/Component/HttpKernel/composer.json
+++ b/src/Symfony/Component/HttpKernel/composer.json
@@ -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": {
@@ -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": {
diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
index 73b5f643a724d..01437d94c7e6a 100644
--- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
+++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
@@ -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 = '';
}
diff --git a/src/Symfony/Component/VarDumper/Dumper/ServerDumper.php b/src/Symfony/Component/VarDumper/Dumper/ServerDumper.php
index 7a25fed61480d..32e1f124cc021 100644
--- a/src/Symfony/Component/VarDumper/Dumper/ServerDumper.php
+++ b/src/Symfony/Component/VarDumper/Dumper/ServerDumper.php
@@ -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.
@@ -21,10 +22,8 @@
*/
class ServerDumper implements DataDumperInterface
{
- private $host;
+ private $connection;
private $wrappedDumper;
- private $contextProviders;
- private $socket;
/**
* @param string $host The server host
@@ -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;
}
}
diff --git a/src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css b/src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css
index babb7ddbbc822..4277c6809bc32 100644
--- a/src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css
+++ b/src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css
@@ -22,14 +22,6 @@ a {
a:hover {
text-decoration: underline;
}
-code {
- color: #cc2255;
- background-color: #f7f7f9;
- border: 1px solid #e1e1e8;
- border-radius: 3px;
- margin-right: 5px;
- padding: 0 3px;
-}
.text-small {
font-size: 12px !important;
}
@@ -60,6 +52,12 @@ article > header > .row > h2 {
article > header > .row > h2 > code {
white-space: nowrap;
user-select: none;
+ color: #cc2255;
+ background-color: #f7f7f9;
+ border: 1px solid #e1e1e8;
+ border-radius: 3px;
+ margin-right: 5px;
+ padding: 0 3px;
}
article > header > .row > time.col {
flex: 0;
diff --git a/src/Symfony/Component/VarDumper/Server/Connection.php b/src/Symfony/Component/VarDumper/Server/Connection.php
new file mode 100644
index 0000000000000..d447b0a98ebc2
--- /dev/null
+++ b/src/Symfony/Component/VarDumper/Server/Connection.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarDumper\Server;
+
+use Symfony\Component\VarDumper\Cloner\Data;
+use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
+
+/**
+ * Forwards serialized Data clones to a server.
+ *
+ * @author Maxime Steinhausser