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:
Fabien Potencier 2019-07-24 12:12:52 +02:00
commit ae2807f6ee
30 changed files with 5 additions and 809 deletions

View File

@ -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;
}
}

View File

@ -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()
;

View File

@ -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;
}
}

View File

@ -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') }}

View File

@ -1,5 +0,0 @@
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
/*
{{ status_code }} {{ status_text }}
*/

View File

@ -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>

View File

@ -1,5 +0,0 @@
{% deprecated 'The template "' ~ _self ~'" is deprecated since Symfony 4.4, will be removed in 5.0.' %}
/*
{{ status_code }} {{ status_text }}
*/

View File

@ -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 }}

View File

@ -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') }}

View File

@ -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.

View File

@ -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 }}" />

View File

@ -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 }) }}

View File

@ -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 }) }}
*/

View File

@ -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>

View File

@ -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 }) }}
*/

View File

@ -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 }}

View File

@ -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 }) }}

View File

@ -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 %}

View File

@ -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>

View File

@ -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 %}

View File

@ -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>

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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>

View File

@ -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 %}

View File

@ -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>

View File

@ -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>

View File

@ -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));
}
}

View File

@ -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: ''

View File

@ -58,24 +58,8 @@ 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']);
return new Response($this->errorRenderer->getBody($exception), 200, ['Content-Type' => 'text/html']);
}
/**
@ -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';
return new Response($this->errorRenderer->getStylesheet(), 200, ['Content-Type' => 'text/css']);
}
}