Reputation: 5597
Instead of an error page / 404 I want to just show the /sitemap page. Of course I don't want a redirect and I still want the 404 HTTP response header to be set.
Is this possible? All I can see is how to set templates in Twig.
I definitely don't want a redirect.
Upvotes: 11
Views: 11108
Reputation: 8355
The easiest way is to create this file:
/app/Resources/TwigBundle/views/Exception/error404.html.twig
/templates/bundles/TwigBundle/Exception/error404.html.twig
... and copy this line into it:
{{ render(controller('App\\Controller\\HomepageController::index')) }}
That's it. This will show the home page with a 404 status code. It only works in prod
environment (clear the cache!), since in dev
and test
Symfony always shows its exception page.
References:
Upvotes: 0
Reputation: 624
I have a simple web app composed by several Symfony3 bundles, all of whose controllers extend a BaseController. I have a AdminBundle too. To show a given page for every not existent url, I hacked (and made simpler) the original ExceptionController.php (from the TwigBundle):
<?php
namespace MyApp\AdminBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use MyApp\Controller\BaseController;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
class ExceptionController extends BaseController
{
/**
* Converts an Exception to a Response.
*
* @param Request $request The request
* @param FlattenException $exception A FlattenException instance
* @param DebugLoggerInterface $logger A DebugLoggerInterface instance
*
* @return Response
* @throws \InvalidArgumentException When the exception template does not exist
*/
public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
{
$currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
$code = $exception->getStatusCode();
return $this->render('MyappAdminBundle:Admin:error.html.twig',
array(
'status_code' => $code,
'status_text' => isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
'exception' => $exception,
'logger' => $logger,
'currentContent' => $currentContent,
)
);
}
/**
* @param int $startObLevel
*
* @return string
*/
protected function getAndCleanOutputBuffering($startObLevel)
{
if (ob_get_level() <= $startObLevel) {
return '';
}
Response::closeOutputBuffers($startObLevel + 1, true);
return ob_get_clean();
}
}
I define my error template as I liked.
I need to add the following line within config.yml
twig:
exception_controller: MyappAdminBundle:Exception:show
ps I am sure my code can be improved, but it works fine.
Upvotes: 0
Reputation: 1749
As shown in the Symfony Cookbook you can override error pages in two ways:
If you only want to show the /sitemap
route on a 404 (HttpNotFoundException
) exception you could override the Twig exception template by creating a new template in app/Resources/TwigBundle/views/Exception/error404.html.twig
.
Another way that is not shown in the cookbook is using an event listener. When the kernel encounters an exception, a kernel.exception
event is dispatched. By default, this exception is caught by the exception listening provided by Twig. You can create your own event listener which listens for the kernel.exception
event and renders a page:
<?php
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
public function onKernelException(GetResponseForExceptionEvent $event)
{
if ($event->getException() instanceof NotFoundHttpException) {
$response = $this->templating->renderResponse(/* sitemap */);
$event->setResponse($response)
}
}
(I haven't tested this code, so you should try it yourself! And you have to inject the templating service into the event listener yourself, of course).
Upvotes: 19