【问题标题】:Symfony2 Unable to find controller inside an EventListenerSymfony2 无法在 EventListener 中找到控制器
【发布时间】:2013-12-03 02:50:35
【问题描述】:

我正在尝试从 EventListener 重定向到控制器,但收到以下错误消息:

Unable to find controller "HRPortalSystemBundle:Home:login"

我肯定 HomeController 存在于 \HRPortal\SystemBundle\Controller 下,并且它确实有一个名为 loginAction() 的方法。这个动作也有一个效果很好的路由:

# routing.yml
login:
    path:    /login
    defaults: { _controller: HRPortalSystemBundle:Home:login }

我的代码如下:

<?php
namespace HRPortal\SystemBundle\EventListener;

use HRPortal\SystemBundle\Controller\TokenAuthenticatedController;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
use Symfony\Component\HttpFoundation\Request;

class TokenListener
{
    private $em;
    private $userRepo;
    private $session;

    public function __construct($em, $session)
    {
        $this->session = $session;
        $this->em = $em;
        $this->userRepo = $em->getRepository('HRPortalSystemBundle:Users');
    }

    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();

        if (!is_array($controller)) {
        return;
        }
        if ($controller[0] instanceof TokenAuthenticatedController) {
            if($this->session->has('id') && $this->session->has('token')){
                $sess_id = $this->session->get('id');
                $sess_token = $this->session->get('token');
                $user = $this->userRepo->findBy(array('id'=>$sess_id, 'token'=>$sess_token));
                if($user == null){
                    throw new AccessDeniedHttpException('We could not find the user');
                }else{
                    if($user->token != $sess_token){
                        throw new AccessDeniedHttpException('This action needs a valid token');
                    }
                }
            }else{
                $request = new Request();
                $resolver = new ControllerResolver();
                $request->attributes->set('_controller', 'HRPortalSystemBundle:Home:login');
                $event->setController($resolver->getController($request));
            }
        }
    }
}

我也不确定 $resolver 是否正确使用,因为我猜这将是解决这个问题后的下一个问题。

提前致谢。

=== 编辑 ===

我已经完成了以下操作,现在它似乎找到了控制器。

$request = new Request();
$resolver = new ControllerResolver();
$request->attributes->set('_controller', 'HRPortal\SystemBundle\Controller\HomeController::loginAction');
$event->setController($resolver->getController($request));

但是,我收到以下错误消息:

Error: Call to a member function get() on a non-object in /usr/local/apache2/htdocs/hrportal/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php line 106

所以控制器和解析器似乎有问题。

【问题讨论】:

    标签: php symfony


    【解决方案1】:

    查看ControllerResolver 源代码后,似乎getController 方法期望_controller 字符串已经转换为Classname::MethodName 格式(或PHP 可调用格式)。

    这个转换是通过ControllerNameParserparse方法完成的。

    【讨论】:

    • 这可能是一个解决方案。我做了一些尝试,但我无法弄清楚在实例化 ControllerNameParser 时应该使用什么 KernelInterface。有什么想法吗?
    【解决方案2】:

    我终于解决了这个问题。感谢 Martin,我使用了 ControllerNameParser 类来解析控制器名称。但我还需要从 services.yml 文件中将容器注入到 EventListener 中。我认为将代码发布给面临同样问题的开发人员会很好:

    Services.yml:

    parameters:
        session_handler.class:    HRPortal\SystemBundle\Services\SessionHandler
        token_listener.class:  HRPortal\SystemBundle\EventListener\TokenListener
        ...
    
    services:
        session_handler:
            class:            "%session_handler.class%"
            arguments:
                em: @doctrine.orm.entity_manager
                session: @session
        tokens_listener:
            class:            "%token_listener.class%"
            arguments:
                em: @doctrine.orm.entity_manager
                container: @service_container
            tags:
                - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
        ...
    

    TokenListener.php

    <?php
    namespace HRPortal\SystemBundle\EventListener;
    
    use HRPortal\SystemBundle\Controller\TokenAuthenticatedController;
    
    use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
    use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
    use Symfony\Component\HttpFoundation\Request;
    
    use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver;
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
    
    class TokenListener extends Controller
    {
        protected $em;
        protected $userRepo;
        protected $container;
    
        public function __construct($em, $container)
        {
            $this->container = $container;
            $this->em = $em;
            $this->userRepo = $em->getRepository('HRPortalSystemBundle:Users');
        }
    
        public function onKernelController(FilterControllerEvent $event)
        {
            $success = false;
            $controller = $event->getController();
    
            if (!is_array($controller)) {
                return;
            }
            if ($controller[0] instanceof TokenAuthenticatedController) {
                $session = $this->container->get('session_handler');
                $loggedIn = $session->isLoggedIn();
                if(!$loggedIn){
                    $request = new Request();
                    $request->attributes->set('_controller', 'HRPortal\SystemBundle\Controller\AuthController::loginAction');
                    $parser = new ControllerNameParser($this->container->get('kernel'));
                    $resolver = new ControllerResolver($this->container, $parser);
                    $event->setController($resolver->getController($request)); 
                }
                return;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多