Page 1 of 1
Best way to return to a referering page from a controller
Posted: Thu Mar 29, 2007 2:24 pm
by Begby
I have a very large site I am working on and would like to be able to return from one controller back to a calling controller after an action is complete.
For instance, from a page with a list of clients there is a link to edit discounts. So you click that and end up at the discounts controller where you can add/edit/delete discounts. When you are done you want to be kicked back to the page with the list of clients.
However, I also want to be able to view discounts for a particular client from another page, say on the shipping page I want to be able to click on a clients highlighted name, edit the discounts, then return the the shipping page.
This was pretty easy at first, I created some methods to set a return url, then a method to redirect back to that return URL. This solves the situations above, so now I can set a referrer, call a controller that executes one or more actions, then return back to the referrer.
Here is where it gets a bit more complicated. I have a list of clients, I want to click on a client to edit that clients details. So I set the referrer back to the list of clients. From the client detail page I want a link to edit discounts. Setting the referrer from that page will return to the client detail page after finishing with discounts, however that will overwrite my original referrer...
I thought about pushing the referrers onto a stack then popping them off as I return up the path, but then if the user uses the back button then things will get all messed up.
Any ideas on how to solve this? If this is all too confusing let me know.
Posted: Thu Mar 29, 2007 4:54 pm
by Christopher
Well ... yes ... it was confusing. I sounds like what you want is an Application Controller. They are usually rule based and save the current status of a sequence of operations in the session. Search around and you may find some info about them. The can get very complex, so you should start simple and solve the problem at hand.
Posted: Thu Mar 29, 2007 8:01 pm
by Begby
Thanks very much arborint, sorry for the confusing post. I'll look into that as it sounds what I am looking for.
Posted: Thu Mar 29, 2007 9:52 pm
by Christopher
An Application Controller is the controller way to do Wizards which in web terms is a series of prerequisite forms. That means that an Application Controller is often (for web apps) a controller of a sequence of a set of Form Controllers.
Posted: Fri Mar 30, 2007 8:12 am
by Begby
I looked up application controllers a bit and am still confused about how I would apply it in code as most of what I found was pretty complex UML diagrams and my head was going to asplode. I think I still need some pointing in the right direction.
A bit of an overview. I am writing a rather large PHP application that is used to run several very large warehouses with people running around like chickens with their heads cut off. They need to be able to get to things within the system quick, so I am making it so on every page a lot of stuff will be clickable for more information. For instance if they are looking at an order for a client, I don't want to force them go to client search to find info for that client, they should be able to access it directly from the order as well as the client search page.
Maybe I can explain it better, I want to be able to access different controllers from different places and have a reuseable controller be able to return you back to where you came from.
Here is an example of of a path between reusable controllers methods
Show list of orders -> /orders/open
Select an order to see detail -> /orders/detail/orderID
Select a product in order to see detail -> /products/detail/prodID
Return to order detail -> /orders/detail/orderID
Return to list of orders ->/orders/open
Here is another one that reuses the product detail
Show list of clients -> /clients/active
Select a client to view details -> /clients/detail/clientID
View products for a client -> /products/forclient/clientID
Select a product to see detail -> /products/detail/prodID
Return to view products -> /products/forclient/clientID
Return to client details -> /client/detail/clientID
Return to list of clients -> /clients/active
And yet another path
Show list of orders -> /orders/open
Select an order to see detail -> /orders/detail/orderID
Click on client name to view client details -> /clients/detail/clientID
View products for client -> /products/forclient/clientID
Return to client detail ->/clients/detail/clientID
Return to order detail -> /orders/detail/orderID
Return to list of orders ->/orders/open
Hopefully that explains it a bit better. I want to be able to access controller methods along a path, then return back along that path by having someone click a done button or having it auto redirect (like after you finish editing an order). The return path is arbitrary, for instance everywhere a client name appears it will be a link to client detail, and everywhere that an order number appears it will be a link to that order detail, there won't be a constant fixed point of return.
Posted: Fri Mar 30, 2007 12:29 pm
by Christopher
Begby wrote:
Show list of orders -> /orders/open
Select an order to see detail -> /orders/detail/orderID
Select a product in order to see detail -> /products/detail/prodID
Return to order detail -> /orders/detail/orderID
Return to list of orders ->/orders/open
Think of the rules you would need to achieve this. Here is some simple and bad code as an example:
Code: Select all
// has prerequisite been met?
if (($url == '/orders/open') && ! $_SESSION['/orders/detail/orderID']) {
$url = '/orders/detail/orderID'; // fall back to prerequisite
}
// has prerequisite been met?
if (($url == '/orders/detail/orderID') && ! $_SESSION['/products/detail/prodID']) {
$url = '/products/detail/prodID'; // fall back to prerequisite
}
// has prerequisite been met?
if (($url == '/products/detail/prodID') && ! $_SESSION['/orders/detail/orderID']) {
$url = '/orders/detail/orderID'; // fall back to prerequisite
}
// has prerequisite been met?
if (($url == '/orders/detail/orderID') && ! $_SESSION['/orders/open']) {
$url = '/orders/open'; // fall back to prerequisite
}
$_SESSION[$url] = true;
Posted: Fri Mar 30, 2007 1:53 pm
by Begby
But its not a matter of rules persay, instead its a matter of telling the destination controller, "Hey, return to me when you are done". It needs to be more arbitrary because designing a set of rules within each controller would be hell, you would need to manually code a rule for every page you linked from.
Here is what I had within a controller
Code: Select all
// This stores a return URL in a session
FCP::response()->setReturnURL($this->getURL()) ;
// At this point I will do stuff and include a links in the view to other controllers that will return to this URL
Then in a controller that had to return
Code: Select all
// This throws an exception if a return url is not set, otherwise unsets the return URL
// and redirects
FCP::response()->autoReturn() ;
The above works fine if the path is only one dimension deep, but what if its more than one deep?
I thought about having a stack like
Code: Select all
// Push a url onto the sequence stack
FCP::response()->pushReturnURL($this->getURL()) ;
// Somewhere else redirect back to the calling controller
FCP::response()->redirect(FCP::response()->popReturnURL()) ;
The problem with the above is that pushing something onto the stack doesn't guarantee that it will get popped. Things will only get popped if the user does something that will autoredirect. If something gets pushed, then they click on something in the main menu, or use the back button, then the sequence array will be hosed.
Another idea I had were to pass the URL as a GET param to the controller, then each controller would have its own session store for the sequence.
Another possibilty would be to have a sequence registry of some sort where you would tell it what controllers you are linking to, or even build it into the a URL object like
Code: Select all
// Get a URL while at the same time setting a return URL
$clientDetailURL = $sequencer->getURL('/client/detail', $this->getURL()) ;
// Return to a URL from within the /client/detail method
FCP::response()->redirect( $sequencer->getReturnURL('/client/detail') ) ;
A pattern for something like this must exist I would imagine
Posted: Fri Mar 30, 2007 2:44 pm
by Christopher
I guess I am not understanding the problem.
If you want a return URL then you would pass that to the Application Controller. It would save it in its session data. The final rule would return the user to that URL when all URLs in the sequence were completed. The Application Controller could also use the return URL for back links on pages to get out of the sequence.
Posted: Mon Apr 02, 2007 8:49 am
by Begby
I think you got it. I'll just figure a way to pass the URL to the application controller like you said, and store it somehow, then return when the sequence in that controller is done.
Thank you very much for your patience in trying to understand me and helping me out.
Posted: Mon Apr 02, 2007 9:07 am
by fastfingertips
The problem i think is a little bit complex because for example sometimes you will need to jump back with two referrers (if you will choose to discounts after you added an user, so you will have to jump back to the user list and not to user add area).
In this case application controller must be combined with an observer (to log user visited pages and their orders). You will set in the application controller the predefined paths and you will use the observer to get the history of the user actions to see where you will redirect the user. I suppose that some controllers are dock ones, meaning that you can reach them from different areas of your application and this situation can be handled only using some logging.