Get previous route and redirect after action (submitting form etc.)

Hi,

Example 1:
I am at a blog-page with a link for edit post. When I click the link the controller (via routes) serves me a form which you can now post.
When I post this edited message I would like to be return to the (first) blog-page I was visiting.
Ps. in this example you have to be logged in.

Example 2:
At any (public) page you can click the ‘login’ button to log-in. After clicking the navigation-button you will be forwarded to the login page.
After the login I do something like:

$this->flash->addMessage('success', 'Welcome, you are logged in.');
return $response->withRedirect($this->router->pathFor('home'));

I would like to adjust ‘home’ also to the current page (before the sign-in page). One note to that: if a user try;s multiple times to login (if he forgets his pass) the page for redirecting has to be the same.

How can I make this kind of thing happen?

Thanks!

I’d use a session variable in both examples. In the first example, when viewing the blog page I assume you only show the edit button to logged in users. At that same point, you can set a session variable, perhaps called ‘redirectAfterSave’ and the value could be the URL of the blog page. After saving the edited post, check for ‘redirectAfterSave’ in the session, and if it exists and is sane, redirect there. If not, redirect somewhere else.

You could do the same kinds of thing with the second example, redirecting after you check the login is valid.

Also see: How to send to the last page after login?

I use a hidden field (or a query parameter for redirects) called r which contains the relative url to where I want to redirect the user.

1 Like

@tflight Tim I am sorry,
I have no clue ‘I cheated and used flash messages to store the referrer in my example app’ what is going on over there. :expressionless:

I think you are pointing at this particulair line of code?

 /**      * Use Slim-Flash to store 'referer' in session      */     
$app->add(function (Request $request, Response $response, callable $next) : Response     
{
$response = $next($request, $response);         
if ($response->getStatusCode() == 200) {             
$this->get('flash')->addMessage('referer', $request->getUri());         
}         
return $response;     });

How does this work? And why should u use the ‘flash’ -> adMessage for it?

@akrabat Rob,
How can I fetch the route?

Let say i use a route : ‘/editpost/123’ where ‘123’ is the number of the post.
And a controller: PageController:editPost.

I can setup something like (in the PageController):

$path = $request->getUri()->getPath();

But gives me /editpost/123 in stead of the blog where I came frome.
How or where do you setup your hidden field ‘r’?

Thanks all!

$router->pathFor('route-name', ['id' => 123]);

In that example the user was using Slim-Flash to store the referrer. That package has an addMessage method that accepts a key and a value (message). The contents of the message are available in the next request (only) so the user was using it to pass in the URL to redirect to, which then made it available in the next request.

Hi Akrabat,

Do you mention something like:

<li class="nav-item">
        <a class="nav-link" href="{{ path_for('auth.signin', {'current_uri': ? }) }}">Login / </a>
</li>

How could I dynamically catch the current uri in the twig? Perhaps you did mention something else?

I dont understand where you accactually setup:
“I use a hidden field (or a query parameter for redirects) called r which contains the relative url to where I want to redirect the user.”

  • in a twig file?

Hi Tim,

I have Slim-Flash for messages.

$container['flash'] = function($container){
	return new \Slim\Flash\Messages;
};

Really not seeing how I could use this to fetch the current uri. I think I am missing some abstract thinking :wink:

You wouldn’t be using Slim-Flash to fetch the URI. Rather you would get the current URI from the request object and then store it in Slim-Flash to be used in the next request.

In the code you linked to above, this is the line where the current URI is added to Slim-Flash’s messages.

$this->get('flash')->addMessage('referer', $request->getUri());

The URI would then be available in the next request by something like this.

$this->get('flash')->getMessages();

I wouldn’t typically do it that way though because I’d often need the URI to be available beyond just the next request. That’s why I store it in a session object. @akrabat’s suggested method of passing it along in a hidden field would work fine too.

Hi Tim,

To set a session variable:

  • How would you do it?
  • To do it in the way of @akrabat : is this a good way:
<li class="nav-item">
        <a class="nav-link" href="{{ path_for('auth.signin', {'current_uri': ? }) }}">Login / </a>
</li>

How could I dynamically catch the current uri in the twig?

Could be as simple as

$_SESSION['redirect_uri'] = $request->getUri();

I use a session object, similar to @akrabat’s rka-slim-session-middleware.

Hi Tim,

If I use this in a controller:

$path = $request->getUri()->getPath();

I am still getting the route I was forwarded to but not the route I came from. OR do I look it in the wrong way and do I need to set a session on the current page (before) you will click a link to ‘go somewhere’ and comeback to the page where you have left.

Correct on your last sentence-- you need to capture the current page, and store that (in a session, flash message, or in a URL parameter) for future requests.

In my apps the logic goes something like this… User tries to access a page, an Authentication Middleware checks they are logged in, if they are not logged in, set the URL they were trying to access in the session, then redirect the user to the login page.

When the user successfully logs in to the app I check to see if there is a session variable with a location to redirect them to. If so, they get redirected to the page they were trying to access and I clear that session variable. If the session variable isn’t set, the users gets whatever page is appropriate for a user that just logged in.

1 Like

Thanks for your effort Tim. Much appriciated.
I will go and try a bunch of things out!

Hi Tim and other,

Still having some questions…

  • Is it a good option to set the session in the controller?
// (Content) Controller

// Get current route & store
$path = $args-> 'some things here';
$_SESSION['current_uri'] = $path;

If I would use a login page I can use the session (something like):

// Login Controller
$login = 'some code and when succes -> redirect';
// Get current URI and redirect
$redirect = ($request->getParam('$_SESSION['current_uri']) ? $request->getParam('$_SESSION['current_uri']) : $this->router->pathFor('home'));
return $response->withRedirect($redirect);

I can imagine that I this case the codes stays clean.
The con can be that it will duplicate code.

P.s. I don’t understand the akrabat code. If I make a new middleware every route (including the login page) gets ‘saved’ in a session?

Setting it in the controller like that is probably fine. You could also create a Trait that other controllers could use and set the session there to avoid duplicate code.

If you want to set it in some sort of middleware then no, don’t apply the middleware to every route. However When talking about akrabat’s middleware, what that is doing is wrapping the $_SESSION variable in an object and then you can access it (the session object) from your controllers. (Many people consider it bad practice to access global variables directly and instead wrap them in objects, which is what that middleware is doing.)