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...