minor #32696 [TwigBundle] remove deprecations and fix tests (Tobion)
This PR was merged into the 5.0-dev branch.
Discussion
----------
[TwigBundle] remove deprecations and fix tests
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | no <!-- please update src/**/CHANGELOG.md files -->
| BC breaks? | yes <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass? | yes <!-- please add some, will be required by reviewers -->
| Fixed tickets |
| License | MIT
| Doc PR |
Removing deprecations from #31398 which should also fix tests in master as I removed some legacy code like (`exception_controller: ~ # to be removed in 5.0 relying on default`) while resolving conflicts when merging 4.4 into master.
Commits
-------
452f66d5e1
[TwigBundle] remove deprecations
This commit is contained in:
commit
ae2807f6ee
@ -1,148 +0,0 @@
|
||||
<?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\TwigBundle\Controller;
|
||||
|
||||
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
|
||||
use Twig\Environment;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Loader\ExistsLoaderInterface;
|
||||
|
||||
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use the ErrorRenderer component instead.', ExceptionController::class), E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* ExceptionController renders error or exception pages for a given
|
||||
* FlattenException.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Matthias Pigulla <mp@webfactory.de>
|
||||
*
|
||||
* @deprecated since Symfony 4.4, use the ErrorRenderer component instead.
|
||||
*/
|
||||
class ExceptionController
|
||||
{
|
||||
protected $twig;
|
||||
protected $debug;
|
||||
|
||||
/**
|
||||
* @param Environment $twig
|
||||
* @param bool $debug Show error (false) or exception (true) pages by default
|
||||
*/
|
||||
public function __construct(Environment $twig, bool $debug)
|
||||
{
|
||||
$this->twig = $twig;
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Exception to a Response.
|
||||
*
|
||||
* A "showException" request parameter can be used to force display of an error page (when set to false) or
|
||||
* the exception page (when true). If it is not present, the "debug" value passed into the constructor will
|
||||
* be used.
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @throws \InvalidArgumentException When the exception template does not exist
|
||||
*/
|
||||
public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
|
||||
{
|
||||
$currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
|
||||
$showException = $request->attributes->get('showException', $this->debug); // As opposed to an additional parameter, this maintains BC
|
||||
|
||||
$code = $exception->getStatusCode();
|
||||
|
||||
return new Response($this->twig->render(
|
||||
(string) $this->findTemplate($request, $request->getRequestFormat(), $code, $showException),
|
||||
[
|
||||
'status_code' => $code,
|
||||
'status_text' => isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
|
||||
'exception' => $exception,
|
||||
'logger' => $logger,
|
||||
'currentContent' => $currentContent,
|
||||
]
|
||||
), 200, ['Content-Type' => $request->getMimeType($request->getRequestFormat()) ?: 'text/html']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $startObLevel
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAndCleanOutputBuffering($startObLevel)
|
||||
{
|
||||
if (ob_get_level() <= $startObLevel) {
|
||||
return '';
|
||||
}
|
||||
|
||||
Response::closeOutputBuffers($startObLevel + 1, true);
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string $format
|
||||
* @param int $code An HTTP response status code
|
||||
* @param bool $showException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function findTemplate(Request $request, $format, $code, $showException)
|
||||
{
|
||||
$name = $showException ? 'exception' : 'error';
|
||||
if ($showException && 'html' == $format) {
|
||||
$name = 'exception_full';
|
||||
}
|
||||
|
||||
// For error pages, try to find a template for the specific HTTP status code and format
|
||||
if (!$showException) {
|
||||
$template = sprintf('@Twig/Exception/%s%s.%s.twig', $name, $code, $format);
|
||||
if ($this->templateExists($template)) {
|
||||
return $template;
|
||||
}
|
||||
}
|
||||
|
||||
// try to find a template for the given format
|
||||
$template = sprintf('@Twig/Exception/%s.%s.twig', $name, $format);
|
||||
if ($this->templateExists($template)) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
// default to a generic HTML exception
|
||||
$request->setRequestFormat('html');
|
||||
|
||||
return sprintf('@Twig/Exception/%s.html.twig', $showException ? 'exception_full' : $name);
|
||||
}
|
||||
|
||||
// to be removed when the minimum required version of Twig is >= 3.0
|
||||
protected function templateExists($template)
|
||||
{
|
||||
$template = (string) $template;
|
||||
|
||||
$loader = $this->twig->getLoader();
|
||||
if ($loader instanceof ExistsLoaderInterface || method_exists($loader, 'exists')) {
|
||||
return $loader->exists($template);
|
||||
}
|
||||
|
||||
try {
|
||||
$loader->getSourceContext($template)->getCode();
|
||||
|
||||
return true;
|
||||
} catch (LoaderError $e) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -35,11 +35,7 @@ class Configuration implements ConfigurationInterface
|
||||
$rootNode
|
||||
->children()
|
||||
->scalarNode('exception_controller')
|
||||
->defaultValue(static function () {
|
||||
@trigger_error('Relying on the default value ("twig.controller.exception::showAction") of the "twig.exception_controller" configuration option is deprecated since Symfony 4.4, set it to "null" explicitly instead, which will be the new default in 5.0.', E_USER_DEPRECATED);
|
||||
|
||||
return 'twig.controller.exception::showAction';
|
||||
})
|
||||
->defaultNull()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
@ -15,8 +15,6 @@ use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface;
|
||||
use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer;
|
||||
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
|
||||
use Twig\Environment;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Loader\ExistsLoaderInterface;
|
||||
|
||||
/**
|
||||
* Provides the ability to render custom Twig-based HTML error pages
|
||||
@ -63,7 +61,6 @@ class TwigHtmlErrorRenderer implements ErrorRendererInterface
|
||||
}
|
||||
|
||||
return $this->twig->render($template, [
|
||||
'legacy' => false, // to be removed in 5.0
|
||||
'exception' => $exception,
|
||||
'status_code' => $exception->getStatusCode(),
|
||||
'status_text' => $exception->getTitle(),
|
||||
@ -73,39 +70,15 @@ class TwigHtmlErrorRenderer implements ErrorRendererInterface
|
||||
private function findTemplate(int $statusCode): ?string
|
||||
{
|
||||
$template = sprintf('@Twig/Exception/error%s.html.twig', $statusCode);
|
||||
if ($this->templateExists($template)) {
|
||||
if ($this->twig->getLoader()->exists($template)) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$template = '@Twig/Exception/error.html.twig';
|
||||
if ($this->templateExists($template)) {
|
||||
if ($this->twig->getLoader()->exists($template)) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be removed in 5.0.
|
||||
*
|
||||
* Use instead:
|
||||
*
|
||||
* $this->twig->getLoader()->exists($template)
|
||||
*/
|
||||
private function templateExists(string $template): bool
|
||||
{
|
||||
$loader = $this->twig->getLoader();
|
||||
if ($loader instanceof ExistsLoaderInterface || method_exists($loader, 'exists')) {
|
||||
return $loader->exists($template);
|
||||
}
|
||||
|
||||
try {
|
||||
$loader->getSourceContext($template);
|
||||
|
||||
return true;
|
||||
} catch (LoaderError $e) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
{{ include('@Twig/Exception/error.xml.twig') }}
|
@ -1,5 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
/*
|
||||
{{ status_code }} {{ status_text }}
|
||||
|
||||
*/
|
@ -1,27 +0,0 @@
|
||||
{% if legacy is not defined or legacy %}
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
{% endif %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="{{ _charset }}" />
|
||||
<title>An Error Occurred: {{ status_text }}</title>
|
||||
<style>
|
||||
body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; }
|
||||
.container { margin: 30px; max-width: 600px; }
|
||||
h1 { color: #dc3545; font-size: 24px; }
|
||||
h2 { font-size: 18px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Oops! An Error Occurred</h1>
|
||||
<h2>The server returned a "{{ status_code }} {{ status_text }}".</h2>
|
||||
|
||||
<p>
|
||||
Something is broken. Please let us know what you were doing when this error occurred.
|
||||
We will fix it as soon as possible. Sorry for any inconvenience caused.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
/*
|
||||
{{ status_code }} {{ status_text }}
|
||||
|
||||
*/
|
@ -1,2 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
{{ { 'error': { 'code': status_code, 'message': status_text } }|json_encode|raw }}
|
@ -1,2 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
{{ include('@Twig/Exception/error.xml.twig') }}
|
@ -1,8 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
Oops! An Error Occurred
|
||||
=======================
|
||||
|
||||
The server returned a "{{ status_code }} {{ status_text }}".
|
||||
|
||||
Something is broken. Please let us know what you were doing when this error occurred.
|
||||
We will fix it as soon as possible. Sorry for any inconvenience caused.
|
@ -1,4 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
<?xml version="1.0" encoding="{{ _charset }}" ?>
|
||||
|
||||
<error code="{{ status_code }}" message="{{ status_text }}" />
|
@ -1,2 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
{{ include('@Twig/Exception/exception.xml.twig', { exception: exception }) }}
|
@ -1,4 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
/*
|
||||
{{ include('@Twig/Exception/exception.txt.twig', { exception: exception }) }}
|
||||
*/
|
@ -1,102 +0,0 @@
|
||||
<div class="exception-summary {{ exception.message is empty ? 'exception-without-message' }}">
|
||||
<div class="exception-metadata">
|
||||
<div class="container">
|
||||
<h2 class="exception-hierarchy">
|
||||
{% for previousException in exception.allPrevious|reverse %}
|
||||
<a href="#trace-box-{{ loop.revindex + 1 }}">{{ previousException.class|abbr_class }}</a>
|
||||
<span class="icon">{{ include('@Twig/images/chevron-right.svg') }}</span>
|
||||
{% endfor %}
|
||||
<a href="#trace-box-1">{{ exception.class|abbr_class }}</a>
|
||||
</h2>
|
||||
<h2 class="exception-http">
|
||||
HTTP {{ status_code }} <small>{{ status_text }}</small>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="exception-message-wrapper">
|
||||
<div class="container">
|
||||
<h1 class="break-long-words exception-message {{ exception.message|length > 180 ? 'long' }}">
|
||||
{{- exception.message|nl2br|format_file_from_text -}}
|
||||
</h1>
|
||||
|
||||
<div class="exception-illustration hidden-xs-down">
|
||||
{{ include('@Twig/images/symfony-ghost.svg') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="sf-tabs">
|
||||
<div class="tab">
|
||||
{% set exception_as_array = exception.toarray %}
|
||||
{% set _exceptions_with_user_code = [] %}
|
||||
{% for i, e in exception_as_array %}
|
||||
{% for trace in e.trace %}
|
||||
{% if (trace.file is not empty) and ('/vendor/' not in trace.file) and ('/var/cache/' not in trace.file) and not loop.last %}
|
||||
{% set _exceptions_with_user_code = _exceptions_with_user_code|merge([i]) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
<h3 class="tab-title">
|
||||
{% if exception_as_array|length > 1 %}
|
||||
Exceptions <span class="badge">{{ exception_as_array|length }}</span>
|
||||
{% else %}
|
||||
Exception
|
||||
{% endif %}
|
||||
</h3>
|
||||
|
||||
<div class="tab-content">
|
||||
{% for i, e in exception_as_array %}
|
||||
{{ include('@Twig/Exception/traces.html.twig', { exception: e, index: loop.index, expand: i in _exceptions_with_user_code or (_exceptions_with_user_code is empty and loop.first) }, with_context = false) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if logger %}
|
||||
<div class="tab {{ logger.logs is empty ? 'disabled' }}">
|
||||
<h3 class="tab-title">
|
||||
Logs
|
||||
{% if logger.counterrors ?? false %}<span class="badge status-error">{{ logger.counterrors }}</span>{% endif %}
|
||||
</h3>
|
||||
|
||||
<div class="tab-content">
|
||||
{% if logger.logs %}
|
||||
{{ include('@Twig/Exception/logs.html.twig', { logs: logger.logs }, with_context = false) }}
|
||||
{% else %}
|
||||
<div class="empty">
|
||||
<p>No log messages</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="tab">
|
||||
<h3 class="tab-title">
|
||||
{% if exception_as_array|length > 1 %}
|
||||
Stack Traces <span class="badge">{{ exception_as_array|length }}</span>
|
||||
{% else %}
|
||||
Stack Trace
|
||||
{% endif %}
|
||||
</h3>
|
||||
|
||||
<div class="tab-content">
|
||||
{% for e in exception_as_array %}
|
||||
{{ include('@Twig/Exception/traces_text.html.twig', { exception: e, index: loop.index, num_exceptions: loop.length }, with_context = false) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if currentContent is not empty %}
|
||||
<div class="tab">
|
||||
<h3 class="tab-title">Output content</h3>
|
||||
|
||||
<div class="tab-content">
|
||||
{{ currentContent }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
@ -1,4 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
/*
|
||||
{{ include('@Twig/Exception/exception.txt.twig', { exception: exception }) }}
|
||||
*/
|
@ -1,2 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
{{ { 'error': { 'code': status_code, 'message': status_text, 'exception': exception.toarray } }|json_encode|raw }}
|
@ -1,2 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
{{ include('@Twig/Exception/exception.xml.twig', { exception: exception }) }}
|
@ -1,8 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
[exception] {{ status_code ~ ' | ' ~ status_text ~ ' | ' ~ exception.class }}
|
||||
[message] {{ exception.message }}
|
||||
{% for i, e in exception.toarray %}
|
||||
[{{ i + 1 }}] {{ e.class }}: {{ e.message }}
|
||||
{{ include('@Twig/Exception/traces.txt.twig', { exception: e }, with_context = false) }}
|
||||
|
||||
{% endfor %}
|
@ -1,10 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
<?xml version="1.0" encoding="{{ _charset }}" ?>
|
||||
|
||||
<error code="{{ status_code }}" message="{{ status_text }}">
|
||||
{% for e in exception.toarray %}
|
||||
<exception class="{{ e.class }}" message="{{ e.message }}">
|
||||
{{ include('@Twig/Exception/traces.xml.twig', { exception: e }, with_context = false) }}
|
||||
</exception>
|
||||
{% endfor %}
|
||||
</error>
|
@ -1,150 +0,0 @@
|
||||
{% extends '@Twig/layout.html.twig' %}
|
||||
|
||||
{% block head %}
|
||||
<style>
|
||||
.sf-reset .traces {
|
||||
padding-bottom: 14px;
|
||||
}
|
||||
.sf-reset .traces li {
|
||||
font-size: 12px;
|
||||
color: #868686;
|
||||
padding: 5px 4px;
|
||||
list-style-type: decimal;
|
||||
margin-left: 20px;
|
||||
}
|
||||
.sf-reset #logs .traces li.error {
|
||||
font-style: normal;
|
||||
color: #AA3333;
|
||||
background: #f9ecec;
|
||||
}
|
||||
.sf-reset #logs .traces li.warning {
|
||||
font-style: normal;
|
||||
background: #ffcc00;
|
||||
}
|
||||
/* fix for Opera not liking empty <li> */
|
||||
.sf-reset .traces li:after {
|
||||
content: "\00A0";
|
||||
}
|
||||
.sf-reset .trace {
|
||||
border: 1px solid #D3D3D3;
|
||||
padding: 10px;
|
||||
overflow: auto;
|
||||
margin: 10px 0 20px;
|
||||
}
|
||||
.sf-reset .block-exception {
|
||||
-moz-border-radius: 16px;
|
||||
-webkit-border-radius: 16px;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f6f6f6;
|
||||
border: 1px solid #dfdfdf;
|
||||
padding: 30px 28px;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
}
|
||||
.sf-reset .block-exception div {
|
||||
color: #313131;
|
||||
font-size: 10px;
|
||||
}
|
||||
.sf-reset .block-exception-detected .illustration-exception,
|
||||
.sf-reset .block-exception-detected .text-exception {
|
||||
float: left;
|
||||
}
|
||||
.sf-reset .block-exception-detected .illustration-exception {
|
||||
width: 152px;
|
||||
}
|
||||
.sf-reset .block-exception-detected .text-exception {
|
||||
width: 670px;
|
||||
padding: 30px 44px 24px 46px;
|
||||
position: relative;
|
||||
}
|
||||
.sf-reset .text-exception .open-quote,
|
||||
.sf-reset .text-exception .close-quote {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
position: absolute;
|
||||
color: #C9C9C9;
|
||||
font-size: 8em;
|
||||
}
|
||||
.sf-reset .open-quote {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.sf-reset .close-quote {
|
||||
bottom: -0.5em;
|
||||
right: 50px;
|
||||
}
|
||||
.sf-reset .block-exception p {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.sf-reset .block-exception p a,
|
||||
.sf-reset .block-exception p a:hover {
|
||||
color: #565656;
|
||||
}
|
||||
.sf-reset .logs h2 {
|
||||
float: left;
|
||||
width: 654px;
|
||||
}
|
||||
.sf-reset .error-count, .sf-reset .support {
|
||||
float: right;
|
||||
width: 170px;
|
||||
text-align: right;
|
||||
}
|
||||
.sf-reset .error-count span {
|
||||
display: inline-block;
|
||||
background-color: #aacd4e;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
color: white;
|
||||
margin-right: 2px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sf-reset .support a {
|
||||
display: inline-block;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
color: #000000;
|
||||
margin-right: 2px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sf-reset .toggle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.sf-reset .linked ul,
|
||||
.sf-reset .linked li {
|
||||
display: inline;
|
||||
}
|
||||
.sf-reset #output-content {
|
||||
color: #000;
|
||||
font-size: 12px;
|
||||
}
|
||||
.sf-reset #traces-text pre {
|
||||
white-space: pre;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
{{ exception.message }} ({{ status_code }} {{ status_text }})
|
||||
{% endblock %}
|
||||
|
||||
{% block before_html %}
|
||||
<!-- {{ exception.message }} ({{ status_code }} {{ status_text }}) -->
|
||||
{% endblock %}
|
||||
|
||||
{% block after_html %}
|
||||
<!-- {{ exception.message }} ({{ status_code }} {{ status_text }}) -->
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{% include '@Twig/Exception/exception.html.twig' %}
|
||||
{% endblock %}
|
@ -1,40 +0,0 @@
|
||||
{% set channel_is_defined = (logs|first).channel is defined %}
|
||||
<table class="logs" data-filter-level="Emergency,Alert,Critical,Error,Warning,Notice,Info,Debug" data-filters>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-filter="level">Level</th>
|
||||
{% if channel_is_defined %}<th data-filter="channel">Channel</th>{% endif %}
|
||||
<th class="full-width">Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for log in logs %}
|
||||
{% if log.priority >= 400 %}
|
||||
{% set status = 'error' %}
|
||||
{% elseif log.priority >= 300 %}
|
||||
{% set status = 'warning' %}
|
||||
{% else %}
|
||||
{% set severity = log.context.exception.severity|default(false) %}
|
||||
{% set status = severity is constant('E_DEPRECATED') or severity is constant('E_USER_DEPRECATED') ? 'warning' : 'normal' %}
|
||||
{% endif %}
|
||||
<tr class="status-{{ status }}" data-filter-level="{{ log.priorityName|lower }}"{% if channel_is_defined %} data-filter-channel="{{ log.channel }}"{% endif %}>
|
||||
<td class="text-small" nowrap>
|
||||
<span class="colored text-bold">{{ log.priorityName }}</span>
|
||||
<span class="text-muted newline">{{ log.timestamp|date('H:i:s') }}</span>
|
||||
</td>
|
||||
{% if channel_is_defined %}
|
||||
<td class="text-small text-bold nowrap">
|
||||
{{ log.channel }}
|
||||
</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
{{ log.message|format_log_message(log.context) }}
|
||||
{% if log.context ?? false %}
|
||||
<pre class="text-muted prewrap m-t-5">{{ log.context|json_encode(constant('JSON_PRETTY_PRINT') b-or constant('JSON_UNESCAPED_UNICODE') b-or constant('JSON_UNESCAPED_SLASHES')) }}</pre>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
@ -1,34 +0,0 @@
|
||||
<div class="trace-line-header break-long-words {{ trace.file|default(false) ? 'sf-toggle' }}" data-toggle-selector="#trace-html-{{ prefix }}-{{ i }}" data-toggle-initial="{{ style == 'expanded' ? 'display' }}">
|
||||
{% if trace.file|default(false) %}
|
||||
<span class="icon icon-close">{{ include('@Twig/images/icon-minus-square.svg') }}</span>
|
||||
<span class="icon icon-open">{{ include('@Twig/images/icon-plus-square.svg') }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if style != 'compact' and trace.function %}
|
||||
<span class="trace-class">{{ trace.class|abbr_class }}</span>{% if trace.type is not empty %}<span class="trace-type">{{ trace.type }}</span>{% endif %}<span class="trace-method">{{ trace.function }}</span><span class="trace-arguments">({{ trace.args|format_args }})</span>
|
||||
{% endif %}
|
||||
|
||||
{% if trace.file|default(false) %}
|
||||
{% set line_number = trace.line|default(1) %}
|
||||
{% set file_link = trace.file|file_link(line_number) %}
|
||||
{% set file_path = trace.file|format_file(line_number)|striptags|replace({ (' at line ' ~ line_number): '' }) %}
|
||||
{% set file_path_parts = file_path|split(constant('DIRECTORY_SEPARATOR')) %}
|
||||
|
||||
<span class="block trace-file-path">
|
||||
in
|
||||
<a href="{{ file_link }}">{{ file_path_parts[:-1]|join(constant('DIRECTORY_SEPARATOR')) }}{{ constant('DIRECTORY_SEPARATOR') }}<strong>{{ file_path_parts|last }}</strong></a>
|
||||
{%- if style == 'compact' and trace.function %}<span class="trace-type">{{ trace.type }}</span><span class="trace-method">{{ trace.function }}</span>{% endif %}
|
||||
(line {{ line_number }})
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if trace.file|default(false) %}
|
||||
<div id="trace-html-{{ prefix ~ '-' ~ i }}" class="trace-code sf-toggle-content">
|
||||
{{ trace.file|file_excerpt(trace.line, 5)|replace({
|
||||
'#DD0000': 'var(--highlight-string)',
|
||||
'#007700': 'var(--highlight-keyword)',
|
||||
'#0000BB': 'var(--highlight-default)',
|
||||
'#FF8000': 'var(--highlight-comment)'
|
||||
})|raw }}
|
||||
</div>
|
||||
{% endif %}
|
@ -1,6 +0,0 @@
|
||||
{% if trace.function %}
|
||||
at {{ trace.class ~ trace.type ~ trace.function }}({{ trace.args|format_args_as_text }})
|
||||
{%- endif -%}
|
||||
{% if trace.file|default('') is not empty and trace.line|default('') is not empty %}
|
||||
{{- trace.function ? '\n (' : 'at '}}{{ trace.file|format_file(trace.line)|striptags|replace({ (' at line ' ~ trace.line): '' }) }}:{{ trace.line }}{{ trace.function ? ')' }}
|
||||
{%- endif %}
|
@ -1,34 +0,0 @@
|
||||
<div class="trace trace-as-html" id="trace-box-{{ index }}">
|
||||
<div class="trace-details">
|
||||
<div class="trace-head">
|
||||
<span class="sf-toggle" data-toggle-selector="#trace-html-{{ index }}" data-toggle-initial="{{ expand ? 'display' }}">
|
||||
<h3 class="trace-class">
|
||||
<span class="icon icon-close">{{ include('@Twig/images/icon-minus-square-o.svg') }}</span>
|
||||
<span class="icon icon-open">{{ include('@Twig/images/icon-plus-square-o.svg') }}</span>
|
||||
|
||||
<span class="trace-namespace">
|
||||
{{ exception.class|split('\\')|slice(0, -1)|join('\\') }}
|
||||
{{- exception.class|split('\\')|length > 1 ? '\\' }}
|
||||
</span>
|
||||
{{ exception.class|split('\\')|last }}
|
||||
</h3>
|
||||
|
||||
{% if exception.message is not empty and index > 1 %}
|
||||
<p class="break-long-words trace-message">{{ exception.message }}</p>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="trace-html-{{ index }}" class="sf-toggle-content">
|
||||
{% set _is_first_user_code = true %}
|
||||
{% for i, trace in exception.trace %}
|
||||
{% set _is_vendor_trace = trace.file is not empty and ('/vendor/' in trace.file or '/var/cache/' in trace.file) %}
|
||||
{% set _display_code_snippet = _is_first_user_code and not _is_vendor_trace %}
|
||||
{% if _display_code_snippet %}{% set _is_first_user_code = false %}{% endif %}
|
||||
<div class="trace-line {{ _is_vendor_trace ? 'trace-from-vendor' }}">
|
||||
{{ include('@Twig/Exception/trace.html.twig', { prefix: index, i: i, trace: trace, style: _is_vendor_trace ? 'compact' : _display_code_snippet ? 'expanded' }, with_context = false) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,10 +0,0 @@
|
||||
{% if exception.trace|length %}
|
||||
{{ exception.class }}:
|
||||
{% if exception.message is not empty %}
|
||||
{{- exception.message }}
|
||||
{% endif %}
|
||||
|
||||
{% for trace in exception.trace %}
|
||||
{{ include('@Twig/Exception/trace.txt.twig', { trace: trace }, with_context = false) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
@ -1,9 +0,0 @@
|
||||
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
|
||||
<traces>
|
||||
{% for trace in exception.trace %}
|
||||
<trace>
|
||||
{{ include('@Twig/Exception/trace.txt.twig', { trace: trace }, with_context = false) }}
|
||||
|
||||
</trace>
|
||||
{% endfor %}
|
||||
</traces>
|
@ -1,30 +0,0 @@
|
||||
<table class="trace trace-as-text">
|
||||
<thead class="trace-head">
|
||||
<tr>
|
||||
<th class="sf-toggle" data-toggle-selector="#trace-text-{{ index }}" data-toggle-initial="{{ 1 == index ? 'display' }}">
|
||||
<h3 class="trace-class">
|
||||
{% if num_exceptions > 1 %}
|
||||
<span class="text-muted">[{{ num_exceptions - index + 1 }}/{{ num_exceptions }}]</span>
|
||||
{% endif %}
|
||||
{{ exception.class|split('\\')|last }}
|
||||
<span class="icon icon-close">{{ include('@Twig/images/icon-minus-square-o.svg') }}</span>
|
||||
<span class="icon icon-open">{{ include('@Twig/images/icon-plus-square-o.svg') }}</span>
|
||||
</h3>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody id="trace-text-{{ index }}">
|
||||
<tr>
|
||||
<td>
|
||||
{% if exception.trace|length %}
|
||||
<pre class="stacktrace">
|
||||
{%- apply escape('html') -%}
|
||||
{{- include('@Twig/Exception/traces.txt.twig', { exception: exception, format: 'html' }, with_context = false) }}
|
||||
{%- endapply -%}
|
||||
</pre>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
@ -1,95 +0,0 @@
|
||||
<?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\TwigBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\TwigBundle\Controller\ExceptionController;
|
||||
use Symfony\Bundle\TwigBundle\Tests\TestCase;
|
||||
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
class ExceptionControllerTest extends TestCase
|
||||
{
|
||||
public function testShowActionCanBeForcedToShowErrorPage()
|
||||
{
|
||||
$twig = $this->createTwigEnv(['@Twig/Exception/error404.html.twig' => '<html>not found</html>']);
|
||||
|
||||
$request = $this->createRequest('html');
|
||||
$request->attributes->set('showException', false);
|
||||
$exception = FlattenException::createFromThrowable(new \Exception(), 404);
|
||||
$controller = new ExceptionController($twig, /* "showException" defaults to --> */ true);
|
||||
|
||||
$response = $controller->showAction($request, $exception, null);
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode()); // successful request
|
||||
$this->assertEquals('<html>not found</html>', $response->getContent());
|
||||
}
|
||||
|
||||
public function testFallbackToHtmlIfNoTemplateForRequestedFormat()
|
||||
{
|
||||
$twig = $this->createTwigEnv(['@Twig/Exception/error.html.twig' => '<html></html>']);
|
||||
|
||||
$request = $this->createRequest('txt');
|
||||
$exception = FlattenException::createFromThrowable(new \Exception());
|
||||
$controller = new ExceptionController($twig, false);
|
||||
|
||||
$controller->showAction($request, $exception);
|
||||
|
||||
$this->assertEquals('html', $request->getRequestFormat());
|
||||
}
|
||||
|
||||
public function testFallbackToHtmlWithFullExceptionIfNoTemplateForRequestedFormatAndExceptionsShouldBeShown()
|
||||
{
|
||||
$twig = $this->createTwigEnv(['@Twig/Exception/exception_full.html.twig' => '<html></html>']);
|
||||
|
||||
$request = $this->createRequest('txt');
|
||||
$request->attributes->set('showException', true);
|
||||
$exception = FlattenException::createFromThrowable(new \Exception());
|
||||
$controller = new ExceptionController($twig, false);
|
||||
|
||||
$controller->showAction($request, $exception);
|
||||
|
||||
$this->assertEquals('html', $request->getRequestFormat());
|
||||
}
|
||||
|
||||
public function testResponseHasRequestedMimeType()
|
||||
{
|
||||
$twig = $this->createTwigEnv(['@Twig/Exception/error.json.twig' => '{}']);
|
||||
|
||||
$request = $this->createRequest('json');
|
||||
$exception = FlattenException::createFromThrowable(new \Exception());
|
||||
$controller = new ExceptionController($twig, false);
|
||||
|
||||
$response = $controller->showAction($request, $exception);
|
||||
|
||||
$this->assertEquals('json', $request->getRequestFormat());
|
||||
$this->assertEquals($request->getMimeType('json'), $response->headers->get('Content-Type'));
|
||||
}
|
||||
|
||||
private function createRequest($requestFormat)
|
||||
{
|
||||
$request = Request::create('whatever');
|
||||
$request->headers->set('X-Php-Ob-Level', 1);
|
||||
$request->setRequestFormat($requestFormat);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
private function createTwigEnv(array $templates)
|
||||
{
|
||||
return new Environment(new ArrayLoader($templates));
|
||||
}
|
||||
}
|
@ -14,7 +14,6 @@ twig:
|
||||
debug: true
|
||||
strict_variables: true
|
||||
default_path: '%kernel.project_dir%/Fixtures/templates'
|
||||
exception_controller: ~ # to be removed in 5.0 relying on default
|
||||
paths:
|
||||
path1: ''
|
||||
path2: ''
|
||||
|
@ -58,26 +58,10 @@ class ExceptionController
|
||||
$this->profiler->disable();
|
||||
|
||||
$exception = $this->profiler->loadProfile($token)->getCollector('exception')->getException();
|
||||
$template = $this->getTemplate();
|
||||
|
||||
if (!$this->twig->getLoader()->exists($template)) {
|
||||
return new Response($this->errorRenderer->getBody($exception), 200, ['Content-Type' => 'text/html']);
|
||||
}
|
||||
|
||||
$code = $exception->getStatusCode();
|
||||
|
||||
return new Response($this->twig->render(
|
||||
$template,
|
||||
[
|
||||
'status_code' => $code,
|
||||
'status_text' => Response::$statusTexts[$code],
|
||||
'exception' => $exception,
|
||||
'logger' => null,
|
||||
'currentContent' => '',
|
||||
]
|
||||
), 200, ['Content-Type' => 'text/html']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the exception panel stylesheet for the given token.
|
||||
*
|
||||
@ -93,17 +77,6 @@ class ExceptionController
|
||||
|
||||
$this->profiler->disable();
|
||||
|
||||
$template = $this->getTemplate();
|
||||
|
||||
if (!$this->twig->getLoader()->exists($template)) {
|
||||
return new Response($this->errorRenderer->getStylesheet(), 200, ['Content-Type' => 'text/css']);
|
||||
}
|
||||
|
||||
return new Response($this->twig->render('@WebProfiler/Collector/exception.css.twig'), 200, ['Content-Type' => 'text/css']);
|
||||
}
|
||||
|
||||
protected function getTemplate()
|
||||
{
|
||||
return '@Twig/Exception/'.($this->debug ? 'exception' : 'error').'.html.twig';
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user