redirect from Presenter always call action <default>
- Václav Novotný
- Member | 13
Hello,
I check user privileges in basePresenter and want conditionaly redirect to “Sign:in”:
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
public function startup()
{
parent::startup();
if (!$this->getUser()->isLoggedIn())
$this->redirect('Sign:in');
}
}
problem is with
$this->redirect('Sign:in')
which calls ‘Sign:default’.
When I use
$this->forward('Sign:in')
it works perfectly, but $this->redirect() always falls to action ‘default’.
My router has two routes, one is REST route and the second is basic route from Nette Sandbox, I don't thik, that problem lies here, but I'm not really sure.
class RouterFactory
{
/**
* @return \Nette\Application\IRouter
*/
public function createRouter()
{
$router = new RouteList();
$router[] = new CrudRoute('api/v1/<presenter>[/<id>/[<relation>[/<relationId>]]]', array(
'module' => 'Api'
));
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
return $router;
}
}
I work on localhost (WAMP, Nette 2.2.3), never before experienced such problem, do anyone have any idea?
Last edited by Václav Novotný (2014-11-03 11:29)
- Václav Novotný
- Member | 13
@Milo that's true, but I wrote simple code to interpret my problem, in fact, I conditionally check presenterName in startup() method to prevent redirect loop
public function startup()
{
parent::startup();
if (!$this->getUser()->isLoggedIn() && $this->getRequest()->getPresenterName() !== 'Sign')
$this->redirect('Sign:in');
}
- Václav Novotný
- Member | 13
I'm really confusing by this. I have traced stack to
Nette\Application\Routers\RouteList
where is method
constructUrl()
/**
* Constructs absolute URL from Request object.
* @return string|NULL
*/
public function constructUrl(Nette\Application\Request $appRequest, Nette\Http\Url $refUrl)
{
if ($this->cachedRoutes === NULL) {
// ...create $this->cachedRoutes;
}
if ($this->module) {
// do somethig...
}
$presenter = strtolower($appRequest->getPresenterName());
if (!isset($this->cachedRoutes[$presenter])) {
$presenter = '*';
}
// added die() here
die(var_dump($appRequest->getParameters()));
foreach ($this->cachedRoutes[$presenter] as $route) {
$url = $route->constructUrl($appRequest, $refUrl);
if ($url !== NULL) {
// added die() here, when $url !== NULL
die(var_dump($appRequest->getParameters()));
return $url;
}
}
return NULL;
}
the first
die(var_dump($appRequest->getParameters()));
outputs
array(2) { ["backlink"]=> string(5) "g7fdt" ["action"]=> string(2) "in" }
which is good ('action' => 'in')
, but when I comment the
first die(...)
and run the app again to get $params
when $url !== NULL
, it
outputs ('action' => 'default')
so the $route->constructUrl
has to run twice. First time when
$appRequest
contains 'action' => 'in'
but it ends
without success (all $url === NULL), so it is called again (somewhere) with
$appRequest
containing 'action' => 'default'
and
this time it succeed to construct URL and do the redirection to
‘Sign:default’.
I'm confused, why it works, when I use $this->forward()
and
not for $this->redirect()
.
@Azathoth: the page is small community server for holding beer
consumption ranks, reviews of different beers and simple accounting of payments
for kegs, therefor all pages are secured, because we do not want our wifes to
easily check our progress :) I implemented your advice so
SignPresenter extends Nette\Application\UI\Presenter
and all other
presenters extends BasePresenter, where is isLoggedIn
check.
Thank you.
- Václav Novotný
- Member | 13
I've catch the problem. Obviously, it was in RouterFactory
class RouterFactory
{
/**
* @return \Nette\Application\IRouter
*/
public function createRouter()
{
$router = new RouteList();
$router[] = new CrudRoute('api/v1/<presenter>[/<id>/[<relation>[/<relationId>]]]', array(
'module' => 'Api'
));
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
return $router;
}
}
the reason, why I never experienced such weirdness before, is because I've
never before used CrudRoute
. If I comment that route out,
everything works good. Don't know, why I did not try this in the
first place…
So the problem is with CrudPresenter, which I've got from drahak/Restful.
At least I know where to dig.
- Václav Novotný
- Member | 13
OK, got it in
Drahak\Restful\Application\Routes\ResourceRoute extends Nette\Application\Routers\Route implements Drahak\Restful\Application\IResourceRouter
in method constructUrl()
on line 142
It changed $appRequest
with
$appRequest->setParameters($params)
in first if
statement
if (count($this->actionDictionary) > 0) {
$params = $appRequest->parameters;
$params['action'] = 'default'; // so the request matches with route with action dictionary
$appRequest->setParameters($params);
}
so I have cloned $appRequest
for that purposes:
if (count($this->actionDictionary) > 0) {
$appRequest = clone $appRequest;
$params = $appRequest->getParameters();
$params['action'] = 'default'; // so the request matches with route with action dictionary
$appRequest->setParameters($params);
}
Maybe not the most elegant way, but it works now.