|
5 | 5 | How to Customize Error Pages |
6 | 6 | ============================ |
7 | 7 |
|
8 | | -When any exception is thrown in Symfony, the exception is caught inside the |
9 | | -``Kernel`` class and eventually forwarded to a special controller, |
10 | | -``TwigBundle:Exception:show`` for handling. This controller, which lives |
11 | | -inside the core TwigBundle, determines which error template to display and |
12 | | -the status code that should be set for the given exception. |
| 8 | +When an exception is thrown, the core ``HttpKernel`` class catches it and |
| 9 | +dispatches a ``kernel.exception`` event. This gives you the power to convert |
| 10 | +the exception into a ``Response`` in a few different ways. |
13 | 11 |
|
14 | | -Error pages can be customized in two different ways, depending on how much |
15 | | -control you need: |
| 12 | +The core TwigBundle sets up a listener for this event which will run |
| 13 | +a configurable (but otherwise arbitrary) controller to generate the |
| 14 | +response. The default controller used has a sensible way of |
| 15 | +picking one out of the available set of error templates. |
16 | 16 |
|
17 | | -1. Customize the error templates of the different error pages; |
| 17 | +Thus, error pages can be customized in different ways, depending on how |
| 18 | +much control you need: |
18 | 19 |
|
19 | | -2. Replace the default exception controller ``twig.controller.exception:showAction``. |
| 20 | +#.:ref:`Use the default ExceptionController and create a few |
| 21 | + templates that allow you to customize how your different error |
| 22 | + pages look (easy); <use-default-exception-controller>` |
20 | 23 |
|
21 | | -ThedefaultExceptionController |
22 | | -------------------------------- |
| 24 | +#.:ref:`Replace thedefaultexception controller with your own |
| 25 | + (intermediate). <custom-exception-controller>` |
23 | 26 |
|
24 | | -The default ``ExceptionController`` will either display an |
| 27 | +#.:ref:`Use the kernel.exception event to come up with your own |
| 28 | + handling (advanced). <use-kernel-exception-event>` |
| 29 | + |
| 30 | +.. _use-default-exception-controller: |
| 31 | + |
| 32 | +Using the Default ExceptionController |
| 33 | +------------------------------------- |
| 34 | + |
| 35 | +By default, the ``showAction()`` method of the |
| 36 | +:class:`Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController` |
| 37 | +will be called when an exception occurs. |
| 38 | + |
| 39 | +This controller will either display an |
25 | 40 | *exception* or *error* page, depending on the setting of the ``kernel.debug`` |
26 | 41 | flag. While *exception* pages give you a lot of helpful |
27 | 42 | information during development, *error* pages are meant to be |
28 | | -shown to theend-user. |
| 43 | +shown to the user in production. |
29 | 44 |
|
30 | 45 | ..sidebar::Testing Error Pages during Development |
31 | 46 |
|
32 | 47 | You should not set ``kernel.debug`` to ``false`` in order to see your |
33 | | - error pages during development. This will also stop |
| 48 | +*error* pages during development. This will also stop |
34 | 49 | Symfony from recompiling your twig templates, among other things. |
35 | 50 |
|
36 | 51 | The third-party `WebfactoryExceptionsBundle`_ provides a special |
37 | 52 | test controller that allows you to display your custom error |
38 | 53 | pages for arbitrary HTTP status codes even with |
39 | 54 | ``kernel.debug`` set to ``true``. |
40 | 55 |
|
41 | | -Override Error Templates |
42 | | ------------------------- |
| 56 | +.. _`WebfactoryExceptionsBundle`:https://github.com/webfactory/exceptions-bundle |
| 57 | + |
| 58 | +.. _cookbook-error-pages-by-status-code: |
| 59 | + |
| 60 | +How the Template for the Error and Exception Pages Is Selected |
| 61 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
43 | 62 |
|
44 | | -All of the error templates live inside the TwigBundle. To override the |
45 | | -templates, simply rely on the standard method for overriding templates that |
46 | | -live inside a bundle. For more information, see |
47 | | -:ref:`overriding-bundle-templates`. |
| 63 | +The TwigBundle contains some default templates for error and |
| 64 | +exception pages in its ``Resources/views/Exception`` directory. |
| 65 | + |
| 66 | +..tip:: |
| 67 | + |
| 68 | + In a standard Symfony installation, the TwigBundle can be found at |
| 69 | + ``vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle``. In addition |
| 70 | + to the standard HTML error page, it also provides a default |
| 71 | + error page for many of the most common response formats, including |
| 72 | + JSON (``error.json.twig``), XML (``error.xml.twig``) and even |
| 73 | + JavaScript (``error.js.twig``), to name a few. |
| 74 | + |
| 75 | +Here is how the ``ExceptionController`` will pick one of the |
| 76 | +available templates based on the HTTP status code and request format: |
| 77 | + |
| 78 | +* For *error* pages, it first looks for a template for the given format |
| 79 | + and status code (like ``error404.json.twig``); |
| 80 | + |
| 81 | +* If that does not exist or apply, it looks for a general template for |
| 82 | + the given format (like ``error.json.twig`` or |
| 83 | + ``exception.json.twig``); |
| 84 | + |
| 85 | +* Finally, it ignores the format and falls back to the HTML template |
| 86 | + (like ``error.html.twig`` or ``exception.html.twig``). |
| 87 | + |
| 88 | +..tip:: |
| 89 | + |
| 90 | + If the exception being handled implements the |
| 91 | +:class:`Symfony\\Component\\HttpKernel\\Exception\\HttpExceptionInterface`, |
| 92 | + the ``getStatusCode()`` method will be |
| 93 | + called to obtain the HTTP status code to use. Otherwise, |
| 94 | + the status code will be "500". |
| 95 | + |
| 96 | +Overriding or Adding Templates |
| 97 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 98 | + |
| 99 | +To override these templates, simply rely on the standard method for |
| 100 | +overriding templates that live inside a bundle. For more information, |
| 101 | +see:ref:`overriding-bundle-templates`. |
48 | 102 |
|
49 | 103 | For example, to override the default error template, create a new |
50 | 104 | template located at |
@@ -74,82 +128,161 @@ template located at |
74 | 128 |
|
75 | 129 | ..tip:: |
76 | 130 |
|
77 | | - If you're not familiar with Twig, don't worry. Twig is a simple, powerful |
78 | | - and optional templating engine that integrates with Symfony. For more |
79 | | - information about Twig see:doc:`/book/templating`. |
| 131 | + If you're not familiar with Twig, don't worry. Twig is a simple, |
| 132 | +powerfuland optional templating engine that integrates with |
| 133 | +Symfony. For moreinformation about Twig see:doc:`/book/templating`. |
80 | 134 |
|
81 | | -In addition to the standard HTML error page, Symfony provides a default error |
82 | | -page for many of the most common response formats, including JSON |
83 | | -(``error.json.twig``), XML (``error.xml.twig``) and even JavaScript |
84 | | -(``error.js.twig``), to name a few. To override any of these templates, just |
85 | | -create a new file with the same name in the |
86 | | -``app/Resources/TwigBundle/views/Exception`` directory. This is the standard |
87 | | -way of overriding any template that lives inside a bundle. |
| 135 | +This works not only to replace the default templates, but also to add |
| 136 | +new ones. |
88 | 137 |
|
89 | | -.. _cookbook-error-pages-by-status-code: |
| 138 | +For instance, create an ``app/Resources/TwigBundle/views/Exception/error404.html.twig`` |
| 139 | +template to display a special page for 404 (page not found) errors. |
| 140 | +Refer to the previous section for the order in which the |
| 141 | +``ExceptionController`` tries different template names. |
90 | 142 |
|
91 | | -Customizing the 404 Page and other Error Pages |
92 | | ----------------------------------------------- |
| 143 | +..tip:: |
93 | 144 |
|
94 | | -You can also customize specific error templates according to the HTTP status |
95 | | -code. For instance, create a |
96 | | -``app/Resources/TwigBundle/views/Exception/error404.html.twig`` template to |
97 | | -display a special page for 404 (page not found) errors. |
| 145 | + Often, the easiest way to customize an error page is to copy it from |
| 146 | + the TwigBundle into ``app/Resources/TwigBundle/views/Exception`` and |
| 147 | + then modify it. |
98 | 148 |
|
99 | | -Symfony uses the following algorithm to determine which template to use: |
| 149 | +..note:: |
100 | 150 |
|
101 | | -* First, it looks for a template for the given format and status code (like |
102 | | - ``error404.json.twig``); |
| 151 | + The debug-friendly exception pages shown to the developer can even be |
| 152 | + customized in the same way by creating templates such as |
| 153 | + ``exception.html.twig`` for the standard HTML exception page or |
| 154 | + ``exception.json.twig`` for the JSON exception page. |
| 155 | + |
| 156 | +.. _custom-exception-controller: |
103 | 157 |
|
104 | | -* If it does not exist, it looks for a template for the given format (like |
105 | | - ``error.json.twig``); |
| 158 | +Replacing the Default ExceptionController |
| 159 | +------------------------------------------ |
| 160 | + |
| 161 | +If you need a little more flexibility beyond just overriding the |
| 162 | +template, then you can change the controller that renders the error |
| 163 | +page. For example, you might need to pass some additional variables into |
| 164 | +your template. |
| 165 | + |
| 166 | +..caution:: |
106 | 167 |
|
107 | | -* If it does not exist, it falls back to the HTML template (like |
108 | | - ``error.html.twig``). |
| 168 | + Make sure you don't lose the exception pages that render the helpful |
| 169 | + error messages during development. |
| 170 | + |
| 171 | +To do this, simply create a new controller and set the |
| 172 | +:ref:`twig.exception_controller<config-twig-exception-controller>` option |
| 173 | +to point to it. |
| 174 | + |
| 175 | +..configuration-block:: |
| 176 | + |
| 177 | + ..code-block::yaml |
| 178 | +
|
| 179 | +# app/config/config.yml |
| 180 | +twig: |
| 181 | +exception_controller:AcmeFooBundle:Exception:showException |
| 182 | +
|
| 183 | + ..code-block::xml |
| 184 | +
|
| 185 | +<!-- app/config/config.xml--> |
| 186 | + <?xml version="1.0" encoding="UTF-8" ?> |
| 187 | + <containerxmlns="http://symfony.com/schema/dic/services" |
| 188 | +xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| 189 | +xmlns:twig="http://symfony.com/schema/dic/twig" |
| 190 | +xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd |
| 191 | + http://symfony.com/schema/dic/twig http://symfony.com/schema/dic/twig/twig-1.0.xsd"> |
| 192 | +
|
| 193 | + <twig:config> |
| 194 | + <twig:exception-controller>AcmeFooBundle:Exception:showException</twig:exception-controller> |
| 195 | + </twig:config> |
| 196 | + </container> |
| 197 | +
|
| 198 | + ..code-block::php |
| 199 | +
|
| 200 | + // app/config/config.php |
| 201 | + $container->loadFromExtension('twig', array( |
| 202 | + 'exception_controller' => 'AcmeFooBundle:Exception:showException', |
| 203 | + // ... |
| 204 | + )); |
109 | 205 |
|
110 | 206 | ..tip:: |
111 | 207 |
|
112 | | - To see the full list of default error templates, see the |
113 | | - ``Resources/views/Exception`` directory of the TwigBundle. In a |
114 | | - standard Symfony installation, the TwigBundle can be found at |
115 | | - ``vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle``. Often, the easiest way |
116 | | - to customize an error page is to copy it from the TwigBundle into |
117 | | - ``app/Resources/TwigBundle/views/Exception`` and then modify it. |
| 208 | + You can also set up your controller as a service. |
118 | 209 |
|
119 | | -..note:: |
| 210 | + The default value of ``twig.controller.exception:showAction`` refers |
| 211 | + to the ``showAction`` method of the ``ExceptionController`` |
| 212 | + described previously, which is registered in the DIC as the |
| 213 | + ``twig.controller.exception`` service. |
120 | 214 |
|
121 | | - The debug-friendly exception pages shown to the developer can even be |
122 | | - customized in the same way by creating templates such as |
123 | | - ``exception.html.twig`` for the standard HTML exception page or |
124 | | - ``exception.json.twig`` for the JSON exception page. |
| 215 | +Your controller will be passed two parameters: ``exception``, |
| 216 | +which is a:class:`\\Symfony\\Component\\Debug\\Exception\\FlattenException` |
| 217 | +instance created from the exception being handled, and ``logger``, |
| 218 | +an instance of:class:`\\Symfony\\Component\\HttpKernel\\Log\\DebugLoggerInterface` |
| 219 | +(which may be ``null``). |
125 | 220 |
|
126 | | -.._`WebfactoryExceptionsBundle`:https://github.com/webfactory/exceptions-bundle |
| 221 | +..tip:: |
127 | 222 |
|
128 | | -Replace the default Exception Controller |
129 | | ----------------------------------------- |
| 223 | + The Request that will be dispatched to your controller is created |
| 224 | + in the:class:`Symfony\\Component\\HttpKernel\\EventListener\\ExceptionListener`. |
| 225 | + This event listener is set up by the TwigBundle. |
130 | 226 |
|
131 | | -If you need a little more flexibility beyond just overriding the template |
132 | | -(e.g. you need to pass some additional variables into your template), |
133 | | -then you can override the controller that renders the error page. |
| 227 | +You can, of course, also extend the previously described |
| 228 | +:class:`Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController`. |
| 229 | +In that case, you might want to override one or both of the |
| 230 | +``showAction`` and ``findTemplate`` methods. The latter one locates the |
| 231 | +template to be used. |
134 | 232 |
|
135 | | -The default exception controller is registered as a service - the actual |
136 | | -class is ``Symfony\Bundle\TwigBundle\Controller\ExceptionController``. |
| 233 | +..caution:: |
137 | 234 |
|
138 | | -To do this, create a new controller class and make it extend Symfony's default |
139 | | -``Symfony\Bundle\TwigBundle\Controller\ExceptionController`` class. |
| 235 | + As of writing, the ``ExceptionController`` is *not* part of the |
| 236 | +Symfony API, so be aware that it might change in following releases. |
140 | 237 |
|
141 | | -There are several methods you can override to customize different parts of how |
142 | | -the error page is rendered. You could, for example, override the entire |
143 | | -``showAction`` or just the ``findTemplate`` method, which locates which |
144 | | -template should be rendered. |
| 238 | +.. _use-kernel-exception-event: |
145 | 239 |
|
146 | | -To make Symfony use your exception controller instead of the default, set the |
147 | | -:ref:`twig.exception_controller<config-twig-exception-controller>` option |
148 | | -in app/config/config.yml. |
| 240 | +Working with the kernel.exception Event |
| 241 | +----------------------------------------- |
| 242 | + |
| 243 | +As mentioned in the beginning, the ``kernel.exception`` event is |
| 244 | +dispatched whenever the Symfony Kernel needs to |
| 245 | +handle an exception. For more information on that, see:ref:`kernel-kernel.exception`. |
| 246 | + |
| 247 | +Working with this event is actually much more powerful than what has |
| 248 | +been explained before but also requires a thorough understanding of |
| 249 | +Symfony internals. |
| 250 | + |
| 251 | +To give one example, assume your application throws |
| 252 | +specialized exceptions with a particular meaning to your domain. |
| 253 | + |
| 254 | +In that case, all the default ``ExceptionListener`` and |
| 255 | +``ExceptionController`` could do for you was trying to figure out the |
| 256 | +right HTTP status code and display your nice-looking error page. |
| 257 | + |
| 258 | +:doc:`Writing your own event listener</cookbook/service_container/event_listener>` |
| 259 | +for the ``kernel.exception`` event allows you to have a closer look |
| 260 | +at the exception and take different actions depending on it. Those |
| 261 | +actions might include logging the exception, redirecting the user to |
| 262 | +another page or rendering specialized error pages. |
| 263 | + |
| 264 | +..note:: |
| 265 | + |
| 266 | + If your listener calls ``setResponse()`` on the |
| 267 | +:class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent`, |
| 268 | + event propagation will be stopped and the response will be sent to |
| 269 | + the client. |
| 270 | + |
| 271 | +This approach allows you to create centralized and layered error |
| 272 | +handling: Instead of catching (and handling) the same exceptions |
| 273 | +in various controllers again and again, you can have just one (or |
| 274 | +several) listeners deal with them. |
149 | 275 |
|
150 | 276 | ..tip:: |
151 | 277 |
|
152 | | - The customization of exception handling is actually much more powerful |
153 | | - than what's written here. An internal event, ``kernel.exception``, is thrown |
154 | | - which allows complete control over exception handling. For more |
155 | | - information, see:ref:`kernel-kernel.exception`. |
| 278 | + To see an example, have a look at the `ExceptionListener`_ in the |
| 279 | + Security Component. |
| 280 | + |
| 281 | + It handles various security-related exceptions that are thrown in |
| 282 | + your application (like:class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException`) |
| 283 | + and takes measures like redirecting the user to the login page, |
| 284 | + logging them out and other things. |
| 285 | + |
| 286 | +Good luck! |
| 287 | + |
| 288 | +.. _`ExceptionListener`:https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php |