I want to redirect admins to /admin
and members to /member
when users are identified but get to the home page (/
).
The controller looks like this :
public function indexAction()
{
if ($this->get('security.context')->isGranted('ROLE_ADMIN'))
{
return new RedirectResponse($this->generateUrl('app_admin_homepage'));
}
else if ($this->get('security.context')->isGranted('ROLE_USER'))
{
return new RedirectResponse($this->generateUrl('app_member_homepage'));
}
return $this->forward('AppHomeBundle:Default:home');
}
If my users are logged in, it works well, no problem. But if they are not, my i18n switch makes me get a nice exception :
The merge filter only works with arrays or hashes in "AppHomeBundle:Default:home.html.twig".
Line that crashes :
{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({'_locale': 'fr'})) }}
If I look at the app.request.get('_route_params')
, it is empty, as well as app.request.get('_route')
.
Of course, I can solve my problem by replacing return $this->forward('AppHomeBundle:Default:home');
by return $this->homeAction();
, but I don't get the point.
Are the internal requests overwritting the user request?
Note: I'm using Symfony version 2.2.1 - app/dev/debug
Looking at the Symfony's source code, when using forward
, a subrequest is created and we are not in the same scope anymore.
/**
* Forwards the request to another controller.
*
* @param string $controller The controller name (a string like BlogBundle:Post:index)
* @param array $path An array of path parameters
* @param array $query An array of query parameters
*
* @return Response A Response instance
*/
public function forward($controller, array $path = array(), array $query = array())
{
$path['_controller'] = $controller;
$subRequest = $this->container->get('request')->duplicate($query, null, $path);
return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
By looking at the Symfony2's scopes documentation, they tell about why request is a scope itself and how to deal with it. But they don't tell about why sub-requests are created when forwarding.
Some more googling put me on the event listeners, where I learnt that the subrequests can be handled (details). Ok, for the sub-request type, but this still does not explain why user request is just removed.
My question becomes :
Why user request is removed and not copied when forwarding?
So, controller actions are separated part of logic. This functions doesn't know anything about each other. My answer is - single action handle kind of specific request (e.g. with specific uri prarams). From SF2 docs (http://symfony.com/doc/current/book/controller.html#requests-controller-response-lifecycle):
2 The Router reads information from the request (e.g. the URI), finds a route that matches that information, and reads the _controller parameter from the route;
3 The controller from the matched route is executed and the code inside the controller creates and returns a Response object;
If your request is for path /
and you wanna inside action (lets say indexAction()
) handling this route, execute another controller action (e.g. fancyAction()
) you should prepare fancyAction()
for that. I mean about using (e.g.):
public function fancyAction($name, $color)
{
// ... create and return a Response object
}
instead:
public function fancyAction()
{
$name = $this->getRequest()->get('name');
$color = $this->getRequest()->get('color');
// ... create and return a Response object
}
Example from sf2 dosc:
public function indexAction($name)
{
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array(
'name' => $name,
'color' => 'green',
));
// ... further modify the response or return it directly
return $response;
}
Please notice further modify the response
.
If you really need request object, you can try:
public function indexAction()
{
// prepare $request for fancyAction
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array('request' => $request));
// ... further modify the response or return it directly
return $response;
}
public function fancyAction(Request $request)
{
// use $request
}