AD7six.com

Making the most of the router

3 May, 2007

Show comments

The router is the part of Cake which takes your url and splits it up so the dispatcher knows which controller and action to run. In 1.1 that's about all it does, but in 1.2 the router also works the other way around too - you can feed it an array of controller, action and paramters and it will tell you which url that corresponds to. All of cakes url using/generating methods are hooked into this (with the exception of requestAction at the time of writing) and below are a few hints on how best to make use of this new magic.

To start at the beginning

If you don't have custom routes, or are just starting out, then code such as the below will look familiar:

<?php
echo $html->link('this is a post with id 1',"/Post/view/1");
?>

There is nothing wrong with writing code such as the above of course, and especially if the magic of cake is still a bit of a mystery it's a good idea to start out using string urls in your code so you can see and know where things are going. After a time writing "NameOfMyController" everywhere, especially if it appears somewhere where you call the code (such as in a common element), you might start writing a few links such as the below:

<?php
echo $html->link('this is a post with id 1',"/".$this->name."/view/1");
?>

Again, nothing wrong with the above, and it's a step closer to more generic code, which in general is a good thing of course. If you have been particularly adventurous with your code, then it's possible that you have some code floating around your application that looks a bit like this:

<?php
// Part of a controller function which needs to redirect to the current controller index
$url = isset($this->params[CAKE_ADMIN])?'/'.CAKE_ADMIN:'';
$url .= $this->plugin?'/'.$this->plugin:'';
$url .= '/'.$this->name;
return $this->redirect($url);
?>

Once again, nothing wrong with the above, and to my mind if you have such code in place and are using 1.1 you are making the most of the possibilities that exist. The only trouble with coding your urls in such a fashion is that you are making an assumption in your code of what your urls look like. If you are not using custom routes this will be of little consequence but if you are, it can become a problem. For example: look take a look at the url for this post "/MiBlog/MakingTheMostOfTheRouter". That url is making use of a custom route - the style and logic for which is defined in my routes file. Using string urls means the logic is duplicated throughout this plugin. If you had exactly the same code as this site on your local machine, but did not have exactly the same routes the application simply doesn't work. So how can the router help solve this...

1.2 - Router on steroids

As I mentioned, and as you may know anyway, in 1.2 you can use an array for just about anywhere within your code that you might want to specify a url. The array keys you can define are what you might expect:

  • CAKE_ADMIN
  • plugin
  • controller
  • action
  • + anything else you would like

Of the 'normal' array keys, for anything you don't define, whatever the current value (or absence of) that array key is used. So, let's have a look at the example link code from above and make that 1.2-y:

<?php
// Verbose definition:
echo $html->link('this is a post with id 1',array(
    'controller'=>'Post',
    'action'=>'view',
    1
));

// If you are currently in the controller Post:
echo $html->link('this is a post with id 1',array(
    'action'=>'view',
    1
));

// If you are currently in the controller Post, and the current action is 'view':
echo $html->link('this is a post with id 1',array(
    1
));

// Full verbose definition (necessary if you are in an admin function, in a plugin):
echo $html->link('this is a post with id 1',array(
    CAKE_ADMIN=>false,
    'plugin'=>false,
    'controller'=>'Post',
    'action'=>'view',
    1
));
?>

For this example what is interesting to note is what you don't need to write - it's never necessary to put something like 'controller'=>$this-name or 'plugin'=>$this->plugin, becuase if you don't write it that's what happens anyway. Just to clarify both of the below functions do exactly the same:

<?php
// Part of a controller function which needs to redirect to the current index function

// Verbose and unnecessary definition:
$url = array(
    CAKE_ADMIN=>isset($this->params[CAKE_ADMIN])?CAKE_ADMIN:false;
    'plugin'=>$this->plugin?$this->plugin:false;
    'controller'=>$this->name,
    'action'=>'index'
);
return $this->redirect($url);

// Take me to my index!
$url = array(
    'action'=>'index'
);
return $this->redirect($url);
?>

And to you that means....?

So apart from meaning you can write arrays instead of strings all over the place what does that mean to you? Let's say that you just ran through the blog tutorial (and converted where appropriate the code used to be 1.2 style), or downloaded some code which made use of array urls everywhere. In addition it's setup to use Slugs. So somewhere in the code the below link is present:

<?php
echo $html->link('Something interesting',array('action'=>'view','SomethingInteresting');
?>

With a default install, it will display a link to the url "/Posts/view/SomethingInteresting". If you decide that you want your urls to look like "/Posts/SomethingInteresting" or "/Noticias/SomethingInteresting" or "Anything/At/All/SomethingIntersting" - if you define a route to do that cake will understand which controller to use when the url is used and generate urls/links which point to your chosen url 'scheme' wherever in your code you used an array to define the url.

Wrapping Up

The router in cake 1.2 uses your (custom) route definitions to decide what to do for a given url and which url to use for a given controller/action (etc.) combination. This makes it simple to consistently make use of custom routes without duplicating logic/assumptions throughout your application code.

Bake on!