Add preview mode support for Html and Serializer error renderers
This commit is contained in:
parent
ac20382f41
commit
38493b3e4b
@ -6,11 +6,22 @@
|
||||
|
||||
<services>
|
||||
<service id="error_handler.error_renderer.html" class="Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer">
|
||||
<argument type="service">
|
||||
<service>
|
||||
<factory class="Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer" method="isDebug" />
|
||||
<argument type="service" id="request_stack" />
|
||||
<argument>%kernel.debug%</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument>%kernel.charset%</argument>
|
||||
<argument type="service" id="debug.file_link_formatter" on-invalid="null" />
|
||||
<argument>%kernel.project_dir%</argument>
|
||||
<argument type="service">
|
||||
<service>
|
||||
<factory class="Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer" method="getAndCleanOutputBuffer" />
|
||||
<argument type="service" id="request_stack" />
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="logger" on-invalid="null" />
|
||||
</service>
|
||||
|
||||
|
@ -163,6 +163,13 @@
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="error_renderer.html" />
|
||||
<argument type="service">
|
||||
<service>
|
||||
<factory class="Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer" method="isDebug" />
|
||||
<argument type="service" id="request_stack" />
|
||||
<argument>%kernel.debug%</argument>
|
||||
</service>
|
||||
</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
@ -36,16 +36,28 @@ class HtmlErrorRenderer implements ErrorRendererInterface
|
||||
private $charset;
|
||||
private $fileLinkFormat;
|
||||
private $projectDir;
|
||||
private $requestStack;
|
||||
private $outputBuffer;
|
||||
private $logger;
|
||||
|
||||
public function __construct(bool $debug = false, string $charset = null, $fileLinkFormat = null, string $projectDir = null, RequestStack $requestStack = null, LoggerInterface $logger = null)
|
||||
/**
|
||||
* @param bool|callable $debug The debugging mode as a boolean or a callable that should return it
|
||||
* @param bool|callable $outputBuffer The output buffer as a string or a callable that should return it
|
||||
*/
|
||||
public function __construct($debug = false, string $charset = null, $fileLinkFormat = null, string $projectDir = null, $outputBuffer = '', LoggerInterface $logger = null)
|
||||
{
|
||||
if (!\is_bool($debug) && !\is_callable($debug)) {
|
||||
throw new \TypeError(sprintf('Argument 1 passed to %s() must be a boolean or a callable, %s given.', __METHOD__, \is_object($debug) ? \get_class($debug) : \gettype($debug)));
|
||||
}
|
||||
|
||||
if (!\is_string($outputBuffer) && !\is_callable($outputBuffer)) {
|
||||
throw new \TypeError(sprintf('Argument 5 passed to %s() must be a string or a callable, %s given.', __METHOD__, \is_object($outputBuffer) ? \get_class($outputBuffer) : \gettype($outputBuffer)));
|
||||
}
|
||||
|
||||
$this->debug = $debug;
|
||||
$this->charset = $charset ?: (ini_get('default_charset') ?: 'UTF-8');
|
||||
$this->fileLinkFormat = $fileLinkFormat ?: (ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'));
|
||||
$this->projectDir = $projectDir;
|
||||
$this->requestStack = $requestStack;
|
||||
$this->outputBuffer = $outputBuffer;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
@ -81,33 +93,26 @@ class HtmlErrorRenderer implements ErrorRendererInterface
|
||||
return $this->include('assets/css/exception.css');
|
||||
}
|
||||
|
||||
private function renderException(FlattenException $exception, string $debugTemplate = 'views/exception_full.html.php'): string
|
||||
public static function isDebug(RequestStack $requestStack, bool $debug): \Closure
|
||||
{
|
||||
$statusText = $this->escape($exception->getStatusText());
|
||||
$statusCode = $this->escape($exception->getStatusCode());
|
||||
|
||||
if (!$this->debug) {
|
||||
return $this->include('views/error.html.php', [
|
||||
'statusText' => $statusText,
|
||||
'statusCode' => $statusCode,
|
||||
]);
|
||||
return static function () use ($requestStack, $debug): bool {
|
||||
if (!$request = $requestStack->getCurrentRequest()) {
|
||||
return $debug;
|
||||
}
|
||||
|
||||
$exceptionMessage = $this->escape($exception->getMessage());
|
||||
$request = $this->requestStack ? $this->requestStack->getCurrentRequest() : null;
|
||||
|
||||
return $this->include($debugTemplate, [
|
||||
'exception' => $exception,
|
||||
'exceptionMessage' => $exceptionMessage,
|
||||
'statusText' => $statusText,
|
||||
'statusCode' => $statusCode,
|
||||
'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null,
|
||||
'currentContent' => $request ? $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1)) : '',
|
||||
]);
|
||||
return $debug && $request->attributes->getBoolean('showException', true);
|
||||
};
|
||||
}
|
||||
|
||||
private function getAndCleanOutputBuffering(int $startObLevel): string
|
||||
public static function getAndCleanOutputBuffer(RequestStack $requestStack): \Closure
|
||||
{
|
||||
return static function () use ($requestStack): string {
|
||||
if (!$request = $requestStack->getCurrentRequest()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$startObLevel = $request->headers->get('X-Php-Ob-Level', -1);
|
||||
|
||||
if (ob_get_level() <= $startObLevel) {
|
||||
return '';
|
||||
}
|
||||
@ -115,6 +120,32 @@ class HtmlErrorRenderer implements ErrorRendererInterface
|
||||
Response::closeOutputBuffers($startObLevel + 1, true);
|
||||
|
||||
return ob_get_clean();
|
||||
};
|
||||
}
|
||||
|
||||
private function renderException(FlattenException $exception, string $debugTemplate = 'views/exception_full.html.php'): string
|
||||
{
|
||||
$debug = \is_bool($this->debug) ? $this->debug : ($this->debug)($exception);
|
||||
$statusText = $this->escape($exception->getStatusText());
|
||||
$statusCode = $this->escape($exception->getStatusCode());
|
||||
|
||||
if (!$debug) {
|
||||
return $this->include('views/error.html.php', [
|
||||
'statusText' => $statusText,
|
||||
'statusCode' => $statusCode,
|
||||
]);
|
||||
}
|
||||
|
||||
$exceptionMessage = $this->escape($exception->getMessage());
|
||||
|
||||
return $this->include($debugTemplate, [
|
||||
'exception' => $exception,
|
||||
'exceptionMessage' => $exceptionMessage,
|
||||
'statusText' => $statusText,
|
||||
'statusCode' => $statusCode,
|
||||
'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null,
|
||||
'currentContent' => \is_string($this->outputBuffer) ? $this->outputBuffer : ($this->outputBuffer)(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -312,7 +343,7 @@ class HtmlErrorRenderer implements ErrorRendererInterface
|
||||
{
|
||||
extract($context, EXTR_SKIP);
|
||||
ob_start();
|
||||
include __DIR__ . '/../Resources/' .$name;
|
||||
include __DIR__.'/../Resources/'.$name;
|
||||
|
||||
return trim(ob_get_clean());
|
||||
}
|
||||
|
@ -26,19 +26,26 @@ class SerializerErrorRenderer implements ErrorRendererInterface
|
||||
private $serializer;
|
||||
private $format;
|
||||
private $fallbackErrorRenderer;
|
||||
private $debug;
|
||||
|
||||
/**
|
||||
* @param string|callable(FlattenException) $format The format as a string or a callable that should return it
|
||||
* @param bool|callable $debug The debugging mode as a boolean or a callable that should return it
|
||||
*/
|
||||
public function __construct(SerializerInterface $serializer, $format, ErrorRendererInterface $fallbackErrorRenderer = null)
|
||||
public function __construct(SerializerInterface $serializer, $format, ErrorRendererInterface $fallbackErrorRenderer = null, $debug = false)
|
||||
{
|
||||
if (!\is_string($format) && !\is_callable($format)) {
|
||||
throw new \TypeError(sprintf('Argument 2 passed to %s() must be a string or a callable, %s given.', __METHOD__, \is_object($format) ? \get_class($format) : \gettype($format)));
|
||||
}
|
||||
|
||||
if (!\is_bool($debug) && !\is_callable($debug)) {
|
||||
throw new \TypeError(sprintf('Argument 4 passed to %s() must be a boolean or a callable, %s given.', __METHOD__, \is_object($debug) ? \get_class($debug) : \gettype($debug)));
|
||||
}
|
||||
|
||||
$this->serializer = $serializer;
|
||||
$this->format = $format;
|
||||
$this->fallbackErrorRenderer = $fallbackErrorRenderer ?? new HtmlErrorRenderer();
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,7 +58,10 @@ class SerializerErrorRenderer implements ErrorRendererInterface
|
||||
try {
|
||||
$format = \is_string($this->format) ? $this->format : ($this->format)($flattenException);
|
||||
|
||||
return $flattenException->setAsString($this->serializer->serialize($flattenException, $format, ['exception' => $exception]));
|
||||
return $flattenException->setAsString($this->serializer->serialize($flattenException, $format, [
|
||||
'exception' => $exception,
|
||||
'debug' => \is_bool($this->debug) ? $this->debug : ($this->debug)($exception),
|
||||
]));
|
||||
} catch (NotEncodableValueException $e) {
|
||||
return $this->fallbackErrorRenderer->render($exception);
|
||||
}
|
||||
|
@ -41,14 +41,15 @@ class ProblemNormalizer implements NormalizerInterface, CacheableSupportsMethodI
|
||||
public function normalize($exception, $format = null, array $context = [])
|
||||
{
|
||||
$context += $this->defaultContext;
|
||||
$debug = $this->debug && $context['debug'] ?? true;
|
||||
|
||||
$data = [
|
||||
'type' => $context['type'],
|
||||
'title' => $context['title'],
|
||||
'status' => $context['status'] ?? $exception->getStatusCode(),
|
||||
'detail' => $this->debug ? $exception->getMessage() : $exception->getStatusText(),
|
||||
'detail' => $debug ? $exception->getMessage() : $exception->getStatusText(),
|
||||
];
|
||||
if ($this->debug) {
|
||||
if ($debug) {
|
||||
$data['class'] = $exception->getClass();
|
||||
$data['trace'] = $exception->getTrace();
|
||||
}
|
||||
|
Reference in New Issue
Block a user