Показывать конкретный маршрут вместо страницы с ошибкой (404) - Symfony2
Вместо страницы с ошибкой /404 я хочу просто показать страницу /sitemap. Конечно, я не хочу перенаправления, и я все же хочу, чтобы заголовок ответа HTTP 404 был установлен.
Возможно ли это? Все, что я вижу, это как установить шаблоны в Twig.
Я определенно не хочу перенаправления.
Ответы
Ответ 1
Как показано в книге по Symfony Cookbook, вы можете переопределять страницы ошибок двумя способами:
- Переопределение шаблонов
- Использование настраиваемого контроллера исключений
Если вы хотите показывать маршрут /sitemap
при исключении 404 (HttpNotFoundException
), вы можете переопределить шаблон исключения Twig, создав новый шаблон в app/Resources/TwigBundle/views/Exception/error404.html.twig
.
Другой способ, который не показан в поваренной книге, - использовать прослушиватель событий. Когда ядро встречает исключение, отправляется событие kernel.exception
. По умолчанию это исключение попадает на прослушивание исключений, предоставляемое Twig. Вы можете создать свой собственный прослушиватель событий, который прослушивает событие kernel.exception
и отображает страницу:
<?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)
}
}
(Я не тестировал этот код, поэтому вы должны попробовать его сами! И вам, конечно же, нужно ввести шаблонный сервис в прослушиватель событий).
Ответ 2
У меня есть простое веб-приложение, состоящее из нескольких пакетов Symfony3, все контроллеры которых расширяют BaseController. У меня также есть AdminBundle. Чтобы показать данную страницу для каждого не существующего URL-адреса, я взломал (и упростил) исходный ExceptionController.php(из 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();
}
}
Я определяю свой шаблон ошибки, как мне понравилось.
Мне нужно добавить следующую строку в config.yml
twig:
exception_controller: MyappAdminBundle:Exception:show
ps Я уверен, что мой код можно улучшить, но он отлично работает.