Skip to content

[DebugBundle] Fix dump/die doesn't work with server dumper #27397

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

Closed
wants to merge 2 commits into from
Closed
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
22 changes: 15 additions & 7 deletions src/Symfony/Bundle/DebugBundle/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,24 @@
</call>
</service>

<service id=".var_dumper.debug_dumper" class="Symfony\Bundle\DebugBundle\VarDumper\DebugDumper">
<argument type="service" id="var_dumper.cli_dumper" />
<argument type="service" id=".var_dumper.context_provider.source" />
<argument>0</argument> <!-- flags -->
<tag name="kernel.event_subscriber" />
</service>

<service id=".var_dumper.context_provider.source" class="Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider">
<argument>%kernel.charset%</argument>
<argument type="string">%kernel.project_dir%</argument>
<argument type="service" id="debug.file_link_formatter" on-invalid="null" />
</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" />
<argument type="service" id=".var_dumper.debug_dumper" />
<argument type="collection">
<argument type="service" key="source">
<service class="Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider">
<argument>%kernel.charset%</argument>
<argument type="string">%kernel.project_dir%</argument>
<argument type="service" id="debug.file_link_formatter" on-invalid="null" />
</service>
<argument type="service" key="source" id=".var_dumper.context_provider.source">
</argument>
<argument type="service" key="request">
<service class="Symfony\Component\VarDumper\Dumper\ContextProvider\RequestContextProvider">
Expand Down
157 changes: 157 additions & 0 deletions src/Symfony/Bundle/DebugBundle/VarDumper/DebugDumper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?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\Bundle\DebugBundle\VarDumper;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;

/**
* Used as fallback in the ServerDumper, it delays output to the end of the process for web requests.
* It replicates the DumpDataCollector behavior to ensure dumps are written to the output
* whenever the dump server isn't up and the debug toolbar not available.
* In cli, output is not delayed and the provided CliDumper instance is used instead.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @internal
*/
final class DebugDumper implements DataDumperInterface, EventSubscriberInterface
{
private $charset;
private $fileLinkFormat;
private $flags;
private $cliDumper;
private $sourceContextProvider;

/** @var array[] */
private $data = array();

public function __construct(CliDumper $cliDumper, SourceContextProvider $sourceContextProvider, int $flags = 0)
{
$this->cliDumper = $cliDumper;
$this->sourceContextProvider = $sourceContextProvider;
$this->flags = $flags;
$this->charset = $this->sourceContextProvider->getCharset();
$this->fileLinkFormat = $this->sourceContextProvider->getFileLinkFormatter();
}

public function dump(Data $data)
{
list('name' => $name, 'file' => $file, 'line' => $line) = $this->sourceContextProvider->getContext();
// only delay web requests
if (\PHP_SAPI !== 'cli' && \PHP_SAPI !== 'phpdbg') {
$this->data[] = array($data, $name, $file, $line);

return;
}

$this->doDump($this->cliDumper, $data, $name, $file, $line);
}

private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line)
{
if ($dumper instanceof CliDumper) {
$contextDumper = function (string $name, string $file, int $line, $fmt) {
if ($this instanceof HtmlDumper) {
if ($file) {
$s = $this->style('meta', '%s');
$f = strip_tags($this->style('', $file));
$name = strip_tags($this->style('', $name));
if ($fmt && $link = is_string($fmt) ? strtr($fmt, array('%f' => $file, '%l' => $line)) : $fmt->format($file, $line)) {
$name = sprintf('<a href="%s" title="%s">'.$s.'</a>', strip_tags($this->style('', $link)), $f, $name);
} else {
$name = sprintf('<abbr title="%s">'.$s.'</abbr>', $f, $name);
}
} else {
$name = $this->style('meta', $name);
}
$this->line = $name.' on line '.$this->style('meta', $line).':';
} else {
$this->line = $this->style('meta', $name).' on line '.$this->style('meta', $line).':';
}
$this->dumpLine(0);
};
$contextDumper = $contextDumper->bindTo($dumper, $dumper);
$contextDumper($name, $file, $line, $this->fileLinkFormat);
} else {
$cloner = new VarCloner();
$dumper->dump($cloner->cloneVar($name.' on line '.$line.':'));
}
$dumper->dump($data);
}

public function __destruct()
{
if ($this->data) {
$h = headers_list();
$i = \count($h);
array_unshift($h, 'Content-Type: '.ini_get('default_mimetype'));
while (0 !== stripos($h[$i], 'Content-Type:')) {
--$i;
}

if (\PHP_SAPI !== 'cli' && \PHP_SAPI !== 'phpdbg' && stripos($h[$i], 'html')) {
$dumper = new HtmlDumper('php://output', $this->charset);
$dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat));
} else {
$dumper = new CliDumper('php://output', $this->charset, $this->flags);
}

foreach ($this->data as list($data, $name, $file, $line)) {
$this->doDump($dumper, $data, $name, $file, $line);
}

$this->data = array();
}
}

public function onKernelResponse(FilterResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}

$response = $event->getResponse();
$request = $event->getRequest();

// In all conditions that remove the web debug toolbar, dumps must be written on the output.
if (
!$response->headers->has('X-Debug-Token')
|| $response->isRedirection()
|| ($response->headers->has('Content-Type') && false === strpos($response->headers->get('Content-Type'), 'html'))
|| 'html' !== $request->getRequestFormat()
|| false === strripos($response->getContent(), '</body>')
) {
return;
}

// Otherwise, empty data and ignore.
$this->data = array();
}

/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
KernelEvents::RESPONSE => array('onKernelResponse', -100),
);
}
}
2 changes: 1 addition & 1 deletion 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
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
* Tries to provide context on CLI.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @final
*/
final class CliContextProvider implements ContextProviderInterface
class CliContextProvider implements ContextProviderInterface
{
public function getContext(): ?array
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
* Tries to provide context from a request.
*
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @final
*/
final class RequestContextProvider implements ContextProviderInterface
class RequestContextProvider implements ContextProviderInterface
{
private $requestStack;
private $cloner;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,21 @@
*
* @author Nicolas Grekas <p@tchwork.com>
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*
* @final
*/
final class SourceContextProvider implements ContextProviderInterface
class SourceContextProvider implements ContextProviderInterface
{
private $limit;
private $charset;
private $projectDir;
private $fileLinkFormatter;

public function __construct(string $charset = null, string $projectDir = null, FileLinkFormatter $fileLinkFormatter = null, int $limit = 9)
public function __construct(string $charset = null, string $projectDir = null, FileLinkFormatter $fileLinkFormatter = null, int $limit = 10)
{
$this->charset = $charset;
$this->charset = $charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8';
$this->projectDir = $projectDir;
$this->fileLinkFormatter = $fileLinkFormatter;
$this->fileLinkFormatter = $fileLinkFormatter ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->limit = $limit;
}

Expand Down Expand Up @@ -110,6 +112,16 @@ public function getContext(): ?array
return $context;
}

public function getCharset(): string
{
return $this->charset;
}

public function getFileLinkFormatter(): ?FileLinkFormatter
{
return $this->fileLinkFormatter;
}

private function htmlEncode(string $s): string
{
$html = '';
Expand Down
14 changes: 6 additions & 8 deletions src/Symfony/Component/VarDumper/Resources/css/htmlDescriptor.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down