Reputation: 176
I am trying to redirect to a controller from the EventListener but I get the following error message:
Unable to find controller "HRPortalSystemBundle:Home:login"
I am affirmative that the HomeController exists under \HRPortal\SystemBundle\Controller and that it does has a method called loginAction(). This action also has a route that works very well:
# routing.yml
login:
path: /login
defaults: { _controller: HRPortalSystemBundle:Home:login }
My code is the following:
<?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));
}
}
}
}
Also I am not sure if the $resolver is used properly, as I guess this will be the next problem after solving this one.
Thanks in advance.
=== EDIT ===
I have done the following, and it seems it now finds the controller.
$request = new Request();
$resolver = new ControllerResolver();
$request->attributes->set('_controller', 'HRPortal\SystemBundle\Controller\HomeController::loginAction');
$event->setController($resolver->getController($request));
However, I get the following error message:
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
So it seems like there's something wrong with the controller and the resolver.
Upvotes: 1
Views: 1718
Reputation: 176
I finally worked out the problem. Thanks to Martin, I used the ControllerNameParser class to parse the Controller name. But I also needed to inject the container inside the EventListener from the services.yml file. I thought it'd be good to post the code for developers facing the same problem:
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;
}
}
}
Upvotes: 0
Reputation: 1187
After having looked at the ControllerResolver
source code, it seems like the getController
method expects the _controller
string to already be converted to a Classname::MethodName
format (or a PHP callable).
This conversion is done by ControllerNameParser
's parse
method.
Upvotes: 2