A continuation from previous question: Custom lithium routing scenario
Note: This is specific to the Lithium Framework
The Problem
I've inherited a URL scheme that doesn't really have any convention to differentiate between pages, items and categories. So, I've got a very generic router that passes to a catch-all controller.
This catch-all controller (PagesController) uses the url as key to retrieve Page Type from a database. The PagesController then runs methods and chooses templates based on a Page Type. I store this information in Memcached indefinitely, so lookups are quite fast.
However, as more page types come into play, I can see this controller becoming too bloated and inflexible. Ideally, I would like to break the different page types out into their own controllers.
The Solution?
Would it be possible to have a routing scenario that checks the database to determine the correct controller?
My first thought is to subclass lithium\net\http\Router
and use custom logic in Router::connect()
and Router::_parseController()
.
It would be nice if could query the database in bootstrap\routes.php and create a new lithium\net\http\Route
object based on the results. Then, simply pass this to Router::connect()
. This seems like an awful hack.
Either way, Router::connect()
in it's design isn't meant to be that dynamic.
It's hard to be very specific, without seeing more examples of different page types and other example URL (I did look at the previous question, but I get the sense that that doesn't give the whole picture), but as with the previous question, it sounds like the answer will once again be custom routing with a handler.
Router::connect('/{:pageType}/{:pageKey}', ['pageKey' => null], function($req) {
$types = ['list', 'of', 'page', 'types'];
$controller = 'pages';
$action = 'view';
if (in_array($req->pageType, $types)) {
// It's a proper type, do a database lookup and set
// `$controller` accordingly
// Here I'm assuming category vs. item view for the action:
$action = $req->pageKey ? 'view' : 'index';
} elseif (!$req->pageKey) {
// It's a `/custom` URL, figure out what to do with it
}
// This lets you return custom, arbitrary parameters that Lithium
// will use for dispatch
return compact('controller', 'action') + $req->params;
});
As you can see, with handlers, you can do pretty much whatever you want. Parse the parameters, run your database calls, and pass back a completely arbitrary set of routing parameters for Lithium to dispatch.
The only other thing you might want to add to the above is a separate class that can manage the pairings between page types/custom pages, and routing parameters, if your rules start getting complicated.