Invalid Article.

Secrets of Admin Routing

By Nate (nate)
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 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 1130

CakePHP Team Comments Author Comments
 

Question

1 Admin Routing for seperated Controllers?

Hi Nate,

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:

<?php 
class NewsController extends AppController {}
?>

Backend:

Controller Class:

<?php 
class Admin_NewsController extends AppController {}
?>

best regards, axel
Posted Jul 17, 2009 by Axel
 

Comment

2 use admin routing

Posted Jul 17, 2009 by ADmad
 

Comment

3 disable admin route on specific link

Hi,

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
Posted Aug 25, 2009 by Tobias Hann
 

Comment

4 Re: disable admin route on specific link

Hi tobi_one,

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
Posted Sep 8, 2009 by Nate
 

Comment

5 redirect()

Nate,

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.
Posted Sep 24, 2009 by Paul Gardner