beforeFilter函数不在Symfony2中重定向

时间:2016-02-02 06:40:19

标签: php symfony

我已经实现了以下代码,可以在任何控制器的任何操作之前运行代码。但是,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() {}

请帮忙,里面缺少什么。 谢谢你的进步

3 个答案:

答案 0 :(得分:2)

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

但是,您无法在FilterControllerEvent上设置响应,因为它要么更新控制器,要么完全更改(setController)。您可以使用其他活动执行此操作,例如kernel.request。但是,您无法访问那里的控制器。

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

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

如果你只需要在控制器中调用你的方法,我就不明白为什么要把事情变得复杂:

public function myAction()
{
    if ($response = $this->beforeFilter()) {
        return $response;
    }

    // ....
}

答案 1 :(得分:2)

我建议您按照setting up before and after filters的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 }

然后,您将创建您的之前的侦听器,它将需要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,然后检查我们是否要重定向,如果是,我们通过回调覆盖整个Controller。这会将重定向响应设置为您的路由并执行重定向。

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

答案 2 :(得分:1)

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);
    });
}

干杯!!