May I perform redirection to another controller within service?
I have implemented a service based on example provided by @Artamiel.
My function code which i
This is possible but I would not recommend it. To redirect from service you should provide proper API
for you event for example like in: FOSUserBundle
where you are receiving instance of FilterUserResponseEvent
and you can set response on that event object:
class RegistrationListener implements EventSubscriberInterface
{
// dependencies
// ...
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_SUCCESS => 'onSuccess',
);
}
public function onSuccess(FilterUserResponseEvent $event)
{
$url = $this->router->generate('some_url');
$event->setResponse(new RedirectResponse($url));
}
}
This is possible thanks to controller:
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);
if (null === $response = $event->getResponse()) {
// create response
}
// return response from event
I don't know how you defined your service but example below works fine. Assuming that you're calling service from your controller.
services.yml
services:
application_backend.service.user:
class: Application\BackendBundle\Service\UserService
arguments:
- @router
Service class
namespace Application\BackendBundle\Service;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
class UserService
{
private $router;
public function __construct(
RouterInterface $router
) {
$this->router = $router;
}
public function create()
{
$user = new User();
$user->setUsername('hello');
$this->entityManager->persist($user);
$this->entityManager->flush();
return new RedirectResponse($this->router->generate('application_frontend_default_index'));
}
}
Controller
public function createAction(Request $request)
{
//.........
return $this->userService->create();
}
UPDATE
Although original answer above answers original question, it is not the best practise so do the following if you want a better way. First of all do not inject @router
into service and do the following changes.
// Service
public function create()
{
.....
$user = new User();
$user->setUsername('hello');
$this->entityManager->persist($user);
$this->entityManager->flush();
.....
}
// Controller
public function createAction(Request $request)
{
try {
$this->userService->create();
return new RedirectResponse($this->router->generate(........);
} catch (......) {
throw new BadRequestHttpException(.....);
}
}
From an architecture point of view one should not create a RedirectResponse
in a service. One way could be to throw an exception in the service, which is caught in the controller's action where you can easily create a RedirectResponse
.
An example can be found here: Redirect from a Service in Symfony2
It seems to make the redirection from service you have to pass to controller either RedirectResponse
object or value that will tell controller that everything within service went fine and no redirection is needed (in example below: "true" value). Then you have to verify in controller which value was provided (whether it is "true" or RedirectResponse
) and either return RedirectResponse
again within controller or do nothing.
Example below should tell everything.
Service:
<?php
namespace AppBundle\Service;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
class nobookchoosenService {
/* @var $request Request */
private $request;
/* @var $router RouterInterface */
private $router;
public function __construct(RequestStack $requestStack, RouterInterface $router) {
$this->request = $requestStack->getCurrentRequest();
$this->router = $router;
}
public function verifyanddispatch() {
$session = $this->request->getSession();
if(!$session->get("App_Books_Chosen_Lp")) return new RedirectResponse($this->router->generate('app_listbooks'));
else return true;
}
}
Controller:
$checker = $this->get('nobookchoosen_service')->verifyanddispatch();
if($checker != "true") return $checker;
I am agree with @Moritz that redirections must be done inside controllers.
But sometimes happens that some redirection would be useful if done from a local function inside a controller.
In this case a solution could be to create a custom Exception Class (RedirectException).
Here you are a link to an interesting post: https://www.trisoft.ro/blog/56-symfony-redirecting-from-outside-the-controller.
I know it's debatable, but has sense if it's used within a local function inside its Controller.
To summarize, the steps would be:
1) Create a RedirectException class
2) Create a Kernel Listener
3) Set Up the Service in the configuration service file (service.yml)
4) Throw an exception with the url to redirect when necessary.