Secrets of Admin Routing
During the CakeFest workshop in Berlin, one of the many topics covered was the routing system. While we touched on most of the general usage patterns, one of the features we didn't go into depth on was admin routing. Unsurprisingly, this is the feature we received the most requests for more information on.
In CakePHP, admin routing is pretty simple: you turn it on, you turn it off, you change the prefix. But there's not much else you can do with it. Right?
I'm about to reveal a little secret about this piece of code:
Download code
It's pretty much irrelevant.
Initially (i.e. 1.1 era and prior), admin routing was fairly static. However, it was refactored in 1.2 such that you could create admin routes (now called 'prefix routes') the same way you create normal routes. The configuration itself was maintained for backwards compatibility, but the following is almost functionally identical:
Download code
I say 'almost' because the one thing that this code does not cover is plugins; but that can be corrected just as simply:
Download code
A quick explanation of the parameters:
Using these flags, you can create as many prefix routes for as many purposes as you want. Keep in mind, however, that these flags do not persist by default. However, you can tell Cake to persist certain parameters automatically, as in this example with PaginatorHelper:
Download code
However, this only applies to URLs generated by PaginatorHelper. To generalize this to all helpers, you can implement a simple check in AppHelper, that works as follows:
Download code
This code can then be extrapolated out to persist any parameters in your application.
Using these techniques, custom prefix routing in CakePHP has never been simpler or more flexible.
I'm about to reveal a little secret about this piece of code:
Download code
Configure::write('Routing.admin', 'admin');
It's pretty much irrelevant.
Initially (i.e. 1.1 era and prior), admin routing was fairly static. However, it was refactored in 1.2 such that you could create admin routes (now called 'prefix routes') the same way you create normal routes. The configuration itself was maintained for backwards compatibility, but the following is almost functionally identical:
Download code
Router::connect('/admin/:controller/:action/*', array(
'action' => null, 'prefix' => 'admin', 'admin' => true
));
I say 'almost' because the one thing that this code does not cover is plugins; but that can be corrected just as simply:
Download code
if ($plugins = Configure::listObjects('plugin')) {
$pluginMatch = implode('|', array_map(array('Inflector', 'underscore'), $plugins));
Router::connect(
"/admin/:plugin/:controller/:action/*",
array('action' => null, 'prefix' => 'admin', 'admin' => true),
array('plugin' => $pluginMatch)
);
}
A quick explanation of the parameters:
- 'prefix' => 'admin' - this is a special routing key which defines the prefix that is appended to the action. Since this key modifies the way in which the request is dispatched, rather than the request itself, it is not factored into reverse routing. Which brings us to the next key...
- 'admin' => true - because the 'prefix' key is not factored into reverse routing, we need a custom flag to differentiate the route, and give us something to check when a request hits this route. While the name of this key matches the value of 'prefix' by convention, this flag can actually be anything, so long as it is not user-modifiable (i.e., not present in the URL template itself).
- 'action' => null - this allows the route to match with or without the action being specified (in which case it defaults to the 'index' action as normal).
- 'plugin' => $pluginMatch - in the plugin route, this key is present in the third parameter to ensure that the :plugin only matches a valid plugin name.
Using these flags, you can create as many prefix routes for as many purposes as you want. Keep in mind, however, that these flags do not persist by default. However, you can tell Cake to persist certain parameters automatically, as in this example with PaginatorHelper:
Download code
$paginator->options(array('url' => array('admin' => true)));
echo $paginator->link('Page 2', array('page' => 2));
However, this only applies to URLs generated by PaginatorHelper. To generalize this to all helpers, you can implement a simple check in AppHelper, that works as follows:
Download code
App::import('Core', 'Helper');
class AppHelper extends Helper {
function url($url = null, $full = false) {
if (isset($this->params['admin']) && is_array($url) && !isset($url['admin'])) {
$url['admin'] = $this->params['admin'];
}
return parent::url($url, $full);
}
}
This code can then be extrapolated out to persist any parameters in your application.
Conclusion
Using these techniques, custom prefix routing in CakePHP has never been simpler or more flexible.
Comments
Question
1 Admin Routing for seperated Controllers?
thank your for the nice article.
Can you tell me if it's possible to do the same prefix-thing with the Controllers instead of Actions? It would be nice if i can make a Controller for the Frontend and one for the Backend.
Frontend:
Controller Class:
<?phpclass NewsController extends AppController {}
?>
Backend:
Controller Class:
<?phpclass Admin_NewsController extends AppController {}
?>
best regards, axel
Comment
2 use admin routing
Comment
3 disable admin route on specific link
great article, thanks!
Is it possible to disable admin routing on a specific link?
I have tried
$html->('link name','/some/url',array('admin' => 'false'); and
$html->('link name','/some/url',array('admin' => 'null')
but neither one works!
Or is it possible to disalbe admin routing "on the fly" alltogether?
Cheers,
tobi_one
Comment
4 Re: disable admin route on specific link
In that example, you're passing the 'admin' flag to the HTML attributes of the link, not to the URL. In order to disable admin routing, you need to use arrays, like so:
$html->link('link name', array('controller' => 'some', 'action' => 'url', 'admin' => false'));
Hope that helps,
- Nate
Comment
5 redirect()
I have just applied this to a little site I am working on and all is great (using the little app_helper snippet too) with my links in the admin area automagically adding the admin_ prefix.
The problem comes when using $this->redirect() in an action after say an add or edit, the admin attribute is being added as admin:1 at the end of my url.
Paul.