在 Symfony2 中不重定向的过滤器函数之前


beforeFilter function not redirecting in Symfony2

我已经实现了以下代码,以便在任何控制器的任何操作之前运行代码。但是,beforeFilter()函数不会重定向到我指定的路由。相反,它将用户带到用户单击的位置。

//My Listener
namespace Edu'AccountBundle'EventListener;
use Symfony'Component'DependencyInjection'Container;
use Symfony'Component'HttpKernel'Event'FilterControllerEvent;
class BeforeControllerListener
{
    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();
        if (!is_array($controller))
        {
            //not a controller do nothing
            return;
        }
        $controllerObject = $controller[0];
        if (is_object($controllerObject) && method_exists($controllerObject, "beforeFilter"))
        //Set a predefined function to execute Before any controller Executes its any method
        {
            $controllerObject->beforeFilter();
        }
    }
}
//I have registered it already
//My Controller
class LedgerController extends Controller
{        
    public function beforeFilter()
    {   
        $commonFunction = new CommonFunctions();
        $dm = $this->getDocumentManager();
        if ($commonFunction->checkFinancialYear($dm) == 0 ) {
            $this->get('session')->getFlashBag()->add('error', 'Sorry');
            return $this->redirect($this->generateUrl('financialyear'));//Here it is not redirecting
        }
    }
}
public function indexAction() {}

请帮忙,里面缺少什么。感谢提前

我建议你遵循Symfony的建议来设置过滤器之前和之后,在过滤器本身中执行你的功能,而不是试图在执行的控制器中创建beforeFilter()函数。 它将允许您实现您想要的 - 在每个控制器操作之前调用的函数 - 以及不必用额外的代码混淆您的控制器。 在您的情况下,您还需要将 Symfony 会话注入到过滤器中:

# app/config/services.yml
services:
    app.before_controller_listener:
        class: AppBundle'EventListener'BeforeControllerListener
        arguments: ['@session', '@router', '@doctrine_mongodb.odm.document_manager']
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

然后,您将创建您的 before 侦听器,它将需要 Symony 会话和路由服务,以及 MongoDB 文档管理器(根据您的配置文件做出假设(。

// src/AppBundle/EventListener/BeforeControllerListener.php
namespace AppBundle'EventListener;
use Doctrine'ODM'MongoDB'DocumentManager;
use Symfony'Bundle'FrameworkBundle'Routing'Router;
use Symfony'Component'HttpFoundation'RedirectResponse;
use Symfony'Component'HttpFoundation'Session'Session;
use Symfony'Component'HttpKernel'Event'FilterControllerEvent;
use AppBundle'Controller'LedgerController;
use AppBundle'Path'To'Your'CommonFunctions;
class BeforeControllerListener
{
    private $session;
    private $router;
    private $documentManager;
    private $commonFunctions;
    public function __construct(Session $session, Router $router, DocumentManager $dm)
    {
        $this->session = $session;
        $this->router = $router;
        $this->dm = $dm;
        $this->commonFunctions = new CommonFunctions();
    }
    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();
        if (!is_array($controller)) {
            return;
        }
        if ($controller[0] instanceof LedgerController) {
            if ($this->commonFunctions->checkFinancialYear($this->dm) !== 0 ) {
                return;
            }
            $this->session->getFlashBag()->add('error', 'Sorry');
            $redirectUrl= $this->router->generate('financialyear');
            $event->setController(function() use ($redirectUrl) {
                return new RedirectResponse($redirectUrl);
            });
        }
    }
}

如果您实际上使用的是Symfony CMF,那么路由器实际上可能ChainRouter,并且路由器的use语句将更改为use Symfony'Cmf'Component'Routing'ChainRouter;

这里还有一些其他的事情,你可能想要重新考虑 - 例如,如果CommonFunctions类需要DocumentManager,你可能只想使CommonFunctions类成为自动注入DocumentManager的服务。 然后,在此服务中,您只需注入通用函数服务而不是文档管理器。

无论哪种方式,这里发生的事情都是我们正在检查我们是否在 LedgerController ,然后检查我们是否要重定向,如果是这样,我们通过回调覆盖整个控制器。 这会设置对路由的重定向响应并执行重定向。

如果您希望对每个控制器进行此检查,则可以简单地消除对LedgerController的检查。.

$this->redirect()控制器函数只是创建一个RedirectResponse的实例。与任何其他响应一样,它需要从控制器返回,或设置在事件上。您的方法不是控制器,因此您必须对事件设置响应。

但是,您不能真正在FilterControllerEvent上设置响应,因为它旨在更新控制器或完全更改它(setController(。您可以使用其他事件来执行此操作,例如 kernel.request .但是,您将无法访问那里的控制器。

您可以尝试使用 setController 设置回调,这将调用您的beforeFilter()。但是,您将无法访问控制器参数,因此如果之前 Filter 没有返回响应,您将无法真正调用原始控制器。

最后,您可以尝试抛出异常并使用异常侦听器处理它。

我不明白如果您可以在控制器中简单地调用您的方法,为什么会使事情变得如此复杂:

public function myAction()
{
    if ($response = $this->beforeFilter()) {
        return $response;
    }
    // ....
}
public function onKernelController(FilterControllerEvent $event)
{
    $request = $event->getRequest();
    $response = new Response();
    // Matched route
    $_route  = $request->attributes->get('_route');
    // Matched controller
    $_controller = $request->attributes->get('_controller');
    $params = array(); //Your params
    $route = $event->getRequest()->get('_route');
    $redirectUrl = $url = $this->container->get('router')->generate($route,$params);

    $event->setController(function() use ($redirectUrl) {
         return new RedirectResponse($redirectUrl);
    });
}

干杯!!