2
votes

I've been following the tips on http://symfony.com/doc/current/cookbook/controller/error_pages.html and created new template error500.html.twig in Resources/TwigBundle/views/Exceptions.

This works fine, but I'd like to have different pages deppending if the user is in the web or admin section of the website.

Is there an easy way to do that? Thank you, Mike.

1

1 Answers

5
votes

I think that the best way to do it is to overriding the default ExceptionController. Just extend it, and override the findTemplate method. Check from the request's attribute if there's _route or _controller set, and do something with it.

namespace AppBundle\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;

class ExceptionController extends BaseExceptionController
{
    protected function findTemplate(Request $request, $format, $code, $showException)
    {
        $routeName = $request->attributes->get('_route');

        // You can inject these routes in the construct of the controller
        // so that you can manage them from the configuration file instead of hardcode them here
        $routesAdminSection = ['admin', 'admin_ban', 'admin_list'];

        // This is a poor implementation with in_array.
        // You can implement more advanced options using regex 
        // so that if you pass "^admin" you can match all the routes that starts with admin.

        // If the route name match, then we want use a different template: admin_error_CODE.FORMAT.twig
        // example: admin_error_404.html.twig
        if (!$showException && in_array($routeName, $routesAdminSection, true)) {
            $template = sprintf('@AppBundle/Exception/admin_error_%s.%s.twig', $code, format);
            if ($this->templateExists($template)) {
                return $template;
            }

            // What you want to do if the template doesn't exist?
            // Just use a generic HTML template: admin_error.html.twig
            $request->setRequestFormat('html');
            return sprintf('@AppBundle/Exception/admin_error.html.twig');
        }

        // Use the default findTemplate method
        return parent::findTemplate($request, $format, $code, $showException);
    }
}

Then configure twig.exception_controller:

# app/config/services.yml
services:
    app.exception_controller:
        class: AppBundle\Controller\ExceptionController
        arguments: ['@twig', '%kernel.debug%']

# app/config/config.yml
twig:
    exception_controller:  app.exception_controller:showAction

You can then override the template in the same way:

  • Resources/AppBundle/views/Exceptions/
    • admin_error.html.twig
    • admin_error_404.html.twig
    • admin_error_500.html.twig
    • ...

UPDATE

A simpler way to do this is to specify the section of the website inside the defaults collection of your routes. Example:

# app/config/routing.yml
home:
    path:      /
    defaults:
        _controller: AppBundle:Main:index
        section:     web
blog:
    path:      /blog/{page}
    defaults:
        _controller: AppBundle:Main:blog
        section:     web
dashboard:
    path:      /admin
    defaults:
        _controller: AppBundle:Admin:dashboard
        section:     admin
stats:
    path:      /admin/stats
    defaults:
        _controller: AppBundle:Admin:stats
        section:     admin

then your controller become something like this:

namespace AppBundle\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;

class ExceptionController extends BaseExceptionController
{
    protected function findTemplate(Request $request, $format, $code, $showException)
    {
        $section = $request->attributes->get('section');
        $template = sprintf('@AppBundle/Exception/%s_error_%s.%s.twig', $section, $code, format);
        if ($this->templateExists($template)) {
            return $template;
        }

        return parent::findTemplate($request, $format, $code, $showException);
    }
}

And configure twig.exception_controller in the same way as described above. Now you just need to define a template for each section, code and format.

  • web_error_404.html.twig
  • web_error_500.html.twig
  • admin_error_404.html.twig
  • admin_error_500.html.twig
  • and so on...