-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Improve cookbook entry for error pages in 2.3~ #4294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,46 +5,100 @@ | |
How to Customize Error Pages | ||
============================ | ||
|
||
When any exception is thrown in Symfony, the exception is caught inside the | ||
``Kernel`` class and eventually forwarded to a special controller, | ||
``TwigBundle:Exception:show`` for handling. This controller, which lives | ||
inside the core TwigBundle, determines which error template to display and | ||
the status code that should be set for the given exception. | ||
When an exception is thrown, the core ``HttpKernel`` class catches it and | ||
dispatches a ``kernel.exception`` event. This gives you the power to convert | ||
the exception into a ``Response`` in a few different ways. | ||
|
||
Error pages can be customized in two different ways, depending on how much | ||
control you need: | ||
The core TwigBundle sets up a listener for this event which will run | ||
a configurable (but otherwise arbitrary) controller to generate the | ||
response. The default controller used has a sensible way of | ||
picking one out of the available set of error templates. | ||
|
||
1. Customize the error templates of the different error pages; | ||
Thus, error pages can be customized in different ways, depending on how | ||
much control you need: | ||
|
||
2. Replace the default exception controller ``twig.controller.exception:showAction``. | ||
#. :ref:`Use the default ExceptionController and create a few | ||
templates that allow you to customize how your different error | ||
pages look (easy); <use-default-exception-controller>` | ||
|
||
The default ExceptionController | ||
------------------------------- | ||
#. :ref:`Replace the default exception controller with your own | ||
(intermediate). <custom-exception-controller>` | ||
|
||
The default ``ExceptionController`` will either display an | ||
#. :ref:`Use the kernel.exception event to come up with your own | ||
handling (advanced). <use-kernel-exception-event>` | ||
|
||
.. _use-default-exception-controller: | ||
|
||
Using the Default ExceptionController | ||
------------------------------------- | ||
|
||
By default, the ``showAction()`` method of the | ||
:class:`Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController` | ||
will be called when an exception occurs. | ||
|
||
This controller will either display an | ||
*exception* or *error* page, depending on the setting of the ``kernel.debug`` | ||
flag. While *exception* pages give you a lot of helpful | ||
information during development, *error* pages are meant to be | ||
shown to the end-user. | ||
shown to the user in production. | ||
|
||
.. sidebar:: Testing Error Pages during Development | ||
|
||
You should not set ``kernel.debug`` to ``false`` in order to see your | ||
error pages during development. This will also stop | ||
*error* pages during development. This will also stop | ||
Symfony from recompiling your twig templates, among other things. | ||
|
||
The third-party `WebfactoryExceptionsBundle`_ provides a special | ||
test controller that allows you to display your custom error | ||
pages for arbitrary HTTP status codes even with | ||
``kernel.debug`` set to ``true``. | ||
|
||
Override Error Templates | ||
------------------------ | ||
.. _`WebfactoryExceptionsBundle`: https://github.com/webfactory/exceptions-bundle | ||
|
||
.. _cookbook-error-pages-by-status-code: | ||
|
||
How the Template for the Error and Exception Pages Is Selected | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
All of the error templates live inside the TwigBundle. To override the | ||
templates, simply rely on the standard method for overriding templates that | ||
live inside a bundle. For more information, see | ||
:ref:`overriding-bundle-templates`. | ||
The TwigBundle contains some default templates for error and | ||
exception pages in its ``Resources/views/Exception`` directory. | ||
|
||
.. tip:: | ||
|
||
In a standard Symfony installation, the TwigBundle can be found at | ||
``vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle``. In addition | ||
to the standard HTML error page, it also provides a default | ||
error page for many of the most common response formats, including | ||
JSON (``error.json.twig``), XML (``error.xml.twig``) and even | ||
JavaScript (``error.js.twig``), to name a few. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "including [...] to name a few" seems incorrect to me (not a native though). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kept that sentence unchanged. |
||
|
||
Here is how the ``ExceptionController`` will pick one of the | ||
available templates based on the HTTP status code and request format: | ||
|
||
* For *error* pages, it first looks for a template for the given format | ||
and status code (like ``error404.json.twig``); | ||
|
||
* If that does not exist or apply, it looks for a general template for | ||
the given format (like ``error.json.twig`` or | ||
``exception.json.twig``); | ||
|
||
* Finally, it ignores the format and falls back to the HTML template | ||
(like ``error.html.twig`` or ``exception.html.twig``). | ||
|
||
.. tip:: | ||
|
||
If the exception being handled implements the | ||
:class:`Symfony\\Component\\HttpKernel\\Exception\\HttpExceptionInterface`, | ||
the ``getStatusCode()`` method will be | ||
called to obtain the HTTP status code to use. Otherwise, | ||
the status code will be "500". | ||
|
||
Overriding or Adding Templates | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
To override these templates, simply rely on the standard method for | ||
overriding templates that live inside a bundle. For more information, | ||
see :ref:`overriding-bundle-templates`. | ||
|
||
For example, to override the default error template, create a new | ||
template located at | ||
|
@@ -74,82 +128,161 @@ template located at | |
|
||
.. tip:: | ||
|
||
If you're not familiar with Twig, don't worry. Twig is a simple, powerful | ||
and optional templating engine that integrates with Symfony. For more | ||
information about Twig see :doc:`/book/templating`. | ||
If you're not familiar with Twig, don't worry. Twig is a simple, | ||
powerful and optional templating engine that integrates with | ||
Symfony. For more information about Twig see :doc:`/book/templating`. | ||
|
||
In addition to the standard HTML error page, Symfony provides a default error | ||
page for many of the most common response formats, including JSON | ||
(``error.json.twig``), XML (``error.xml.twig``) and even JavaScript | ||
(``error.js.twig``), to name a few. To override any of these templates, just | ||
create a new file with the same name in the | ||
``app/Resources/TwigBundle/views/Exception`` directory. This is the standard | ||
way of overriding any template that lives inside a bundle. | ||
This works not only to replace the default templates, but also to add | ||
new ones. | ||
|
||
.. _cookbook-error-pages-by-status-code: | ||
For instance, create an ``app/Resources/TwigBundle/views/Exception/error404.html.twig`` | ||
template to display a special page for 404 (page not found) errors. | ||
Refer to the previous section for the order in which the | ||
``ExceptionController`` tries different template names. | ||
|
||
Customizing the 404 Page and other Error Pages | ||
---------------------------------------------- | ||
.. tip:: | ||
|
||
You can also customize specific error templates according to the HTTP status | ||
code. For instance, create a | ||
``app/Resources/TwigBundle/views/Exception/error404.html.twig`` template to | ||
display a special page for 404 (page not found) errors. | ||
Often, the easiest way to customize an error page is to copy it from | ||
the TwigBundle into ``app/Resources/TwigBundle/views/Exception`` and | ||
then modify it. | ||
|
||
Symfony uses the following algorithm to determine which template to use: | ||
.. note:: | ||
|
||
* First, it looks for a template for the given format and status code (like | ||
``error404.json.twig``); | ||
The debug-friendly exception pages shown to the developer can even be | ||
customized in the same way by creating templates such as | ||
``exception.html.twig`` for the standard HTML exception page or | ||
``exception.json.twig`` for the JSON exception page. | ||
|
||
.. _custom-exception-controller: | ||
|
||
* If it does not exist, it looks for a template for the given format (like | ||
``error.json.twig``); | ||
Replacing the Default ExceptionController | ||
------------------------------------------ | ||
|
||
If you need a little more flexibility beyond just overriding the | ||
template, then you can change the controller that renders the error | ||
page. For example, you might need to pass some additional variables into | ||
your template. | ||
|
||
.. caution:: | ||
|
||
* If it does not exist, it falls back to the HTML template (like | ||
``error.html.twig``). | ||
Make sure you don't lose the exception pages that render the helpful | ||
error messages during development. | ||
|
||
To do this, simply create a new controller and set the | ||
:ref:`twig.exception_controller <config-twig-exception-controller>` option | ||
to point to it. | ||
|
||
.. configuration-block:: | ||
|
||
.. code-block:: yaml | ||
|
||
# app/config/config.yml | ||
twig: | ||
exception_controller: AcmeFooBundle:Exception:showException | ||
|
||
.. code-block:: xml | ||
|
||
<!-- app/config/config.xml --> | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<container xmlns="http://symfony.com/schema/dic/services" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns:twig="http://symfony.com/schema/dic/twig" | ||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd | ||
http://symfony.com/schema/dic/twig http://symfony.com/schema/dic/twig/twig-1.0.xsd"> | ||
|
||
<twig:config> | ||
<twig:exception-controller>AcmeFooBundle:Exception:showException</twig:exception-controller> | ||
</twig:config> | ||
</container> | ||
|
||
.. code-block:: php | ||
|
||
// app/config/config.php | ||
$container->loadFromExtension('twig', array( | ||
'exception_controller' => 'AcmeFooBundle:Exception:showException', | ||
// ... | ||
)); | ||
|
||
.. tip:: | ||
|
||
To see the full list of default error templates, see the | ||
``Resources/views/Exception`` directory of the TwigBundle. In a | ||
standard Symfony installation, the TwigBundle can be found at | ||
``vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle``. Often, the easiest way | ||
to customize an error page is to copy it from the TwigBundle into | ||
``app/Resources/TwigBundle/views/Exception`` and then modify it. | ||
You can also set up your controller as a service. | ||
|
||
.. note:: | ||
The default value of ``twig.controller.exception:showAction`` refers | ||
to the ``showAction`` method of the ``ExceptionController`` | ||
described previously, which is registered in the DIC as the | ||
``twig.controller.exception`` service. | ||
|
||
The debug-friendly exception pages shown to the developer can even be | ||
customized in the same way by creating templates such as | ||
``exception.html.twig`` for the standard HTML exception page or | ||
``exception.json.twig`` for the JSON exception page. | ||
Your controller will be passed two parameters: ``exception``, | ||
which is a :class:`\\Symfony\\Component\\Debug\\Exception\\FlattenException` | ||
instance created from the exception being handled, and ``logger``, | ||
an instance of :class:`\\Symfony\\Component\\HttpKernel\\Log\\DebugLoggerInterface` | ||
(which may be ``null``). | ||
|
||
.. _`WebfactoryExceptionsBundle`: https://github.com/webfactory/exceptions-bundle | ||
.. tip:: | ||
|
||
Replace the default Exception Controller | ||
---------------------------------------- | ||
The Request that will be dispatched to your controller is created | ||
in the :class:`Symfony\\Component\\HttpKernel\\EventListener\\ExceptionListener`. | ||
This event listener is set up by the TwigBundle. | ||
|
||
If you need a little more flexibility beyond just overriding the template | ||
(e.g. you need to pass some additional variables into your template), | ||
then you can override the controller that renders the error page. | ||
You can, of course, also extend the previously described | ||
:class:`Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController`. | ||
In that case, you might want to override one or both of the | ||
``showAction`` and ``findTemplate`` methods. The latter one locates the | ||
template to be used. | ||
|
||
The default exception controller is registered as a service - the actual | ||
class is ``Symfony\Bundle\TwigBundle\Controller\ExceptionController``. | ||
.. caution:: | ||
|
||
To do this, create a new controller class and make it extend Symfony's default | ||
``Symfony\Bundle\TwigBundle\Controller\ExceptionController`` class. | ||
As of writing, the ``ExceptionController`` is *not* part of the | ||
Symfony API, so be aware that it might change in following releases. | ||
|
||
There are several methods you can override to customize different parts of how | ||
the error page is rendered. You could, for example, override the entire | ||
``showAction`` or just the ``findTemplate`` method, which locates which | ||
template should be rendered. | ||
.. _use-kernel-exception-event: | ||
|
||
To make Symfony use your exception controller instead of the default, set the | ||
:ref:`twig.exception_controller <config-twig-exception-controller>` option | ||
in app/config/config.yml. | ||
Working with the kernel.exception Event | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would enclose |
||
----------------------------------------- | ||
|
||
As mentioned in the beginning, the ``kernel.exception`` event is | ||
dispatched whenever the Symfony Kernel needs to | ||
handle an exception. For more information on that, see :ref:`kernel-kernel.exception`. | ||
|
||
Working with this event is actually much more powerful than what has | ||
been explained before but also requires a thorough understanding of | ||
Symfony internals. | ||
|
||
To give one example, assume your application throws | ||
specialized exceptions with a particular meaning to your domain. | ||
|
||
In that case, all the default ``ExceptionListener`` and | ||
``ExceptionController`` could do for you was trying to figure out the | ||
right HTTP status code and display your nice-looking error page. | ||
|
||
:doc:`Writing your own event listener </cookbook/service_container/event_listener>` | ||
for the ``kernel.exception`` event allows you to have a closer look | ||
at the exception and take different actions depending on it. Those | ||
actions might include logging the exception, redirecting the user to | ||
another page or rendering specialized error pages. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nicely explained |
||
|
||
.. note:: | ||
|
||
If your listener calls ``setResponse()`` on the | ||
:class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent`, | ||
event propagation will be stopped and the response will be sent to | ||
the client. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't the default one have the lowest-possible priority? If so, I don't think we need the first part of this note. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it has a low priority (meaning that registering your listener with the default priority of 0 will make it run before the core one). But it is not the lowest-possible priority (it is possible to build lower integers in PHP, as we are still far from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure - there's nothing special in the TwigBundle config, so I'd say it's the "default" priority and your own one must be better than that (i. e. non-default)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mpdude It's an event subscriber - so it's inside the class - it's -128. So if you don't do anything, your listener will be called first :). |
||
|
||
This approach allows you to create centralized and layered error | ||
handling: Instead of catching (and handling) the same exceptions | ||
in various controllers again and again, you can have just one (or | ||
several) listeners deal with them. | ||
|
||
.. tip:: | ||
|
||
The customization of exception handling is actually much more powerful | ||
than what's written here. An internal event, ``kernel.exception``, is thrown | ||
which allows complete control over exception handling. For more | ||
information, see :ref:`kernel-kernel.exception`. | ||
To see an example, have a look at the `ExceptionListener`_ in the | ||
Security Component. | ||
|
||
It handles various security-related exceptions that are thrown in | ||
your application (like :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException`) | ||
and takes measures like redirecting the user to the login page, | ||
logging them out and other things. | ||
|
||
Good luck! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! :D |
||
|
||
.. _`ExceptionListener`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like including the numbers when you have a mini-table of contents like we do here. In fact, I really like how you organized things. We could even link the above lines down to each section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you show me an example for such in-page links please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! If the header were
Customize Error Templates
, then you would have:See `Customize Error Templates`_