|
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 |
| -The default ExceptionController |
22 |
| -------------------------------- |
| 24 | +#. :ref:`Replace the default exception 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 the end-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 | + powerful and optional templating engine that integrates with |
| 133 | + Symfony. For more information 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 | + <container xmlns="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 |
0 commit comments