1111
1212namespace Symfony \Bundle \TwigBundle \Controller ;
1313
14+ use Symfony \Component \ErrorHandler \ErrorRenderer \ErrorRenderer ;
15+ use Symfony \Component \ErrorHandler \ErrorRenderer \HtmlErrorRenderer ;
16+ use Symfony \Component \ErrorHandler \ErrorRenderer \JsonErrorRenderer ;
17+ use Symfony \Component \ErrorHandler \ErrorRenderer \TxtErrorRenderer ;
18+ use Symfony \Component \ErrorHandler \ErrorRenderer \XmlErrorRenderer ;
19+ use Symfony \Component \ErrorHandler \Exception \ErrorRendererNotFoundException ;
1420use Symfony \Component \ErrorHandler \Exception \FlattenException ;
1521use Symfony \Component \HttpFoundation \Request ;
1622use Symfony \Component \HttpFoundation \Response ;
17- use Symfony \Component \HttpKernel \Log \DebugLoggerInterface ;
1823use Twig \Environment ;
1924use Twig \Error \LoaderError ;
2025use Twig \Loader \ExistsLoaderInterface ;
@@ -30,15 +35,22 @@ class ExceptionController
3035{
3136protected $ twig ;
3237protected $ debug ;
38+ private $ errorRenderer ;
3339
3440/**
3541 * @param Environment $twig
3642 * @param bool $debug Show error (false) or exception (true) pages by default
3743 */
38- public function __construct (Environment $ twig ,bool $ debug )
44+ public function __construct (Environment $ twig ,bool $ debug, ErrorRenderer $ errorRenderer = null )
3945 {
4046$ this ->twig =$ twig ;
4147$ this ->debug =$ debug ;
48+ $ this ->errorRenderer =$ errorRenderer ??new ErrorRenderer ([
49+ new HtmlErrorRenderer ($ debug ),
50+ new JsonErrorRenderer ($ debug ),
51+ new XmlErrorRenderer ($ debug ),
52+ new TxtErrorRenderer ($ debug ),
53+ ]);
4254 }
4355
4456/**
@@ -49,26 +61,12 @@ public function __construct(Environment $twig, bool $debug)
4961 * be used.
5062 *
5163 * @return Response
52- *
53- * @throws \InvalidArgumentException When the exception template does not exist
5464 */
55- public function showAction (Request $ request ,FlattenException $ exception, DebugLoggerInterface $ logger = null )
65+ public function showAction (Request $ request ,FlattenException $ exception )
5666 {
57- $ currentContent =$ this ->getAndCleanOutputBuffering ($ request ->headers ->get ('X-Php-Ob-Level ' , -1 ));
58- $ showException =$ request ->attributes ->get ('showException ' ,$ this ->debug );// As opposed to an additional parameter, this maintains BC
59-
60- $ code =$ exception ->getStatusCode ();
61-
62- return new Response ($ this ->twig ->render (
63- (string )$ this ->findTemplate ($ request ,$ request ->getRequestFormat (),$ code ,$ showException ),
64- [
65- 'status_code ' =>$ code ,
66- 'status_text ' =>isset (Response::$ statusTexts [$ code ]) ? Response::$ statusTexts [$ code ] :'' ,
67- 'exception ' =>$ exception ,
68- 'logger ' =>$ logger ,
69- 'currentContent ' =>$ currentContent ,
70- ]
71- ),200 , ['Content-Type ' =>$ request ->getMimeType ($ request ->getRequestFormat ()) ?:'text/html ' ]);
67+ return new Response ($ this ->render ($ exception ,$ request ),200 , [
68+ 'Content-Type ' =>$ request ->getMimeType ($ request ->getRequestFormat ())
69+ ]);
7270 }
7371
7472/**
@@ -94,32 +92,45 @@ protected function getAndCleanOutputBuffering($startObLevel)
9492 * @param bool $showException
9593 *
9694 * @return string
95+ *
96+ * @deprecated since Symfony 4.4
9797 */
9898protected function findTemplate (Request $ request ,$ format ,$ code ,$ showException )
9999 {
100- $ name =$ showException ?'exception ' :'error ' ;
101- if ($ showException &&'html ' ==$ format ) {
102- $ name ='exception_full ' ;
100+ @trigger_error (sprintf ('The "%s()" method is deprecated since Symfony 4.4, use "findTwigTemplate()" method instead. ' ,__METHOD__ ),E_USER_DEPRECATED );
101+
102+ if ($ template =$ this ->findTwigTemplate ($ code ,$ format ,$ showException )) {
103+ return $ template ;
103104 }
104105
106+ // default to a generic HTML exception
107+ $ request ->setRequestFormat ('html ' );
108+
109+ return sprintf ('@Twig/Exception/%s.html.twig ' ,$ showException ?'exception_full ' :'error ' );
110+ }
111+
112+ protected function findTwigTemplate (int $ statusCode ,string $ format ,bool $ showException ): ?string
113+ {
105114// For error pages, try to find a template for the specific HTTP status code and format
106115if (!$ showException ) {
107- $ template =sprintf ('@Twig/Exception/%s%s .%s.twig ' ,$ name , $ code ,$ format );
116+ $ template =sprintf ('@Twig/Exception/error%s .%s.twig ' ,$ statusCode ,$ format );
108117if ($ this ->templateExists ($ template )) {
109118return $ template ;
110119 }
111120 }
112121
122+ $ name ='error ' ;
123+ if ($ showException ) {
124+ $ name ='html ' ===$ format ?'exception_full ' :'exception ' ;
125+ }
126+
113127// try to find a template for the given format
114128$ template =sprintf ('@Twig/Exception/%s.%s.twig ' ,$ name ,$ format );
115129if ($ this ->templateExists ($ template )) {
116130return $ template ;
117131 }
118132
119- // default to a generic HTML exception
120- $ request ->setRequestFormat ('html ' );
121-
122- return sprintf ('@Twig/Exception/%s.html.twig ' ,$ showException ?'exception_full ' :$ name );
133+ return null ;
123134 }
124135
125136// to be removed when the minimum required version of Twig is >= 3.0
@@ -141,4 +152,32 @@ protected function templateExists($template)
141152
142153return false ;
143154 }
155+
156+ private function render (FlattenException $ exception ,Request $ request ):string
157+ {
158+ $ statusCode =$ exception ->getStatusCode ();
159+ $ logger =$ request ->attributes ->get ('logger ' );
160+ $ showException =$ request ->attributes ->get ('showException ' ,$ this ->debug );
161+ $ currentContent =$ this ->getAndCleanOutputBuffering ($ request ->headers ->get ('X-Php-Ob-Level ' , -1 ));
162+
163+ $ template =$ this ->findTwigTemplate ($ statusCode ,$ request ->getRequestFormat (),$ showException );
164+
165+ if (null ===$ template ) {
166+ try {
167+ // fallback to the native renderer system
168+ return $ this ->errorRenderer ->render ($ exception ,$ request ->getRequestFormat ());
169+ }catch (ErrorRendererNotFoundException $ e ) {
170+ $ request ->setRequestFormat ('html ' );
171+ $ template =sprintf ('@Twig/Exception/%s.html.twig ' ,$ showException ?'exception_full ' :'error ' );
172+ }
173+ }
174+
175+ return $ this ->twig ->render ($ template , [
176+ 'status_code ' =>$ statusCode ,
177+ 'status_text ' => Response::$ statusTexts [$ statusCode ] ??'' ,
178+ 'exception ' =>$ exception ,
179+ 'logger ' =>$ logger ,
180+ 'currentContent ' =>$ currentContent ,
181+ ]);
182+ }
144183}