如何为特定控制器操作创建异常事件侦听器,以使用其原始参数重定向到另一个操作


How to create exception event listener for a specific controller action, to redirect to another action using its original argument?

我有一个接受参数的动作,路线如下所示:

/cs/{id}

它是Cassette控制器中的individualAction

有时,500 Internal Server Error - NoResultException有一个例外 - 这是预期行为。

我希望重定向到另一个控制器操作,editAction ,发生这种情况时,路由如下:

/cs/{id}/edit

它需要特定于控制器,因为我想用不同的控制器操作重复此操作。它还需要使参数远离原始操作。

我一直在研究事件侦听器,但我不确定这是否矫枉过正,我正在努力找出如何使它们特定于操作 - 如果这是更好的解决方案,我很乐意将代码保存在控制器中。

EventListener最适合在

引发异常时更改应用的外观。

使用类似以下内容:

<?php
namespace AppBundle'EventListener;
use Symfony'Component'HttpFoundation'RedirectResponse;
use Symfony'Component'HttpKernel'Event'GetResponseForExceptionEvent;
use Symfony'Component'Routing'RouterInterface;
use Doctrine'ORM'NoResultException;
class ExceptionResponseListener
{
    public function __construct(RouterInterface $router)
    {
        $this->router = $router;
    }
    /**
     * @param GetResponseForExceptionEvent $event
     */
    public function onKernelResponse(GetResponseForExceptionEvent $event)
    {
        $request = $event->getRequest();
        $routeName = $request->get('_route');
        $exception = $event->getException();
        // Restrict the route by adding a check on the route name
        // Or a pattern of route names (!strpos($routeName, '_show'))
        // Or for many routes: (!in_array($routeName, ['xxx_show', ...]
        // Or the _controller: $request->get('_controller')
        // Output something like: "AcmeBundle''Controller''DefaultController::showAction"
        if ('expected_route_name' !== $routeName) {
            return;
        }    
        // Retrieve your param
        $params = $request->get('_route_params');
        if ($exception instanceof NoResultException) {
            // Create a redirection to the edit route
            $response = new RedirectResponse(
                $this->router->generate('your_edit_route', array('id' => $params['id']))
            );
            $event->setResponse($response);
        }
    }
}

并将其注册为服务:

services:
    # ...
    acme.kernel.listener.exception_listener:
        class: AppBundle'EventListener'ExceptionResponseListener
        tags:
            - {name: kernel.event_listener, event: kernel.exception, method: onKernelResponse}
        arguments: ['@router']

另一种简单的替代方法是直接在方法中对预期操作进行转发/重定向,而不是引发异常。