Kohana 2.3 Routing

Published on:
Tags: Personal

Kohana Routing In my last post I mentioned that there’s a change in the works for Kohana 2.3, and I wasn’t lying! If you watch the forum then you will of certainly seen some discussions on it, of particular note are:Routing in 2.3 and 2.3 Routing Examples.

I think initially the change was met with skepticism , as these things so often are, people don’t like future compatibility issues, which is understandable, but in this case I think the additional advantage gained is great enough to offset this potential cause of frustration. Hopefully this post will outline some of those benefits to you, allowing you to make up your own mind!

Configuration So the first thing you will notice is that routing is now configured differently, imo when you get to grips with that is going on then it is actually now SIMPLER to setup more complex routes, you can now achieve scenarios with equal or greater flexibility to those of before but without the use of any regular expressions. The new default route is as follows:

$config['default'] = array
(
    // Default routing
    ':controller/:method/:id',
    // Defaults for route keys
    'controller' => 'welcome',
    'method' => 'index',
);

$config[‘default’] Now this may or may not appear self-explanatory, we’ll go through it anyway! Routes are now given a name, this route is called ‘default’, the name itself is not technically important, though we will come to their usage later! ‘:controller/:method/:id’ This is the definition of our routing arguments, prefixing a segment with a colon ‘:’ makes it a router argument, and interpretable as such, :controller and :method are ignored as arguments and if present are used as you would imagine (:controller is used as the request controller, :method for the method) ‘controller’ => ‘welcome’,‘method’ => ‘index’, Here we set the defaults, this basically says that if the controller is not present then use the ‘welcome’ controller and the ‘index’ method within it. If controller is present with no method then use the index method within whichever controller Play Time Confused? maybe, but with that under our belt we can now start playing around with this. Best way to get to grips with this is to grab a checkout of the development head (http://source.kohanaphp.com/trunk (or http://dev.kohanaphp.com/browser/trunk if your more graphically inclined)) and set yourself up a sandbox! Once installed if you go to your local address you should be presented with the nice new green welcome page. New Controller Create yourself a new controller ‘Page’ (remember controllers are now defined as ‘class Controller_Page’), and give it an empty index method which echos your favorite hello world substitute before exiting. Going to <your-site>/page will now show you your hello world substitute. This behavior shouldn’t bowl you off your feet, in fact the more astute will probably of noticed that this is exactly the same as with the previous (read current) release!. Going to <your-site>/page/index will provide the same, <your- site>/page/index/12 will give the same again (notice the trend),  <your- site>/page/index/12/long WILL BREAK however, this is in contrast to previous (current) versions in which we could continue to add War and Peace after the matched route and the framework would continue to hurry us along without any problem, this gives us MUCH tighter control over our routes and could potentially provide security benefits (I havn’t worked through that scenario yet – any input?). It means if we want to capture data then we have to define it within our route.

If we wanted to capture that fourth segment potentially then we could change our default route to:

$config['default'] = array
(
    // Default routing
    ':controller/:method/:id/:style',
    // Defaults for route keys
    'controller' => 'welcome',
    'method' => 'index',
);

Above we have added another router argument called ‘style’, visiting our page with 4 segments no longer gives us an error … making any more sense yet?

Accessing URI parameters (arguments) So above we have seen how to add additional parameters to the route, how can we access these named parameters? Router::$arguments is the answer, add to your index method in your page controller the following, then visit your four segment route again:

    var_dump(router::$arguments['style']);

Very nice. We now have a nice, unified way of accessing these named parameters.

Practical Example So lets now run quickly through a practical example to demonstrate some more of the functionality we can leverage from this . .yes there is more!

Lets re-use our page controller and add a blog_posts function to it. We define the following route:

$config['blog_post'] = array
(
    // Default routing
    'post/:year/:month/:day',
    // Defaults for route keys
    'controller'    => 'page',
    'method'    => 'blog_post',
    'year'      => date('Y'),
    //Ensure we get the correct date formats!
    'regex'     => array(
                'year'  => '[0-9]{4}',
                'month' => '[0-9]{2}',
                'day'   => '[0-9]{2}'
                )
);

The above has introduced the regex functionality, hopefully it is relatively self-explanatory there. We can basically provide individual regex patterns for each of our defined url arguments, which makes for some really nice and simple pattern matching options. Also note how we define our default year to be the current one, very simple, very effective and very future proof! All from the routing configuration.

Add the below function into your Page controller (from before):

public function blog_post()
{
  $year     = router::$arguments['year'];
  $month    = isset(router::$arguments['month']) ? router::$arguments['month'] : null ;
  $day  = isset(router::$arguments['day']) ? router::$arguments['day'] : null ;
  echo "Blog Post";
  var_dump($year);
  var_dump($month);
  var_dump($day);
  exit;
}

Now visit <your-site>/post and you should see what is going on here! I think that the set up we’re looking at here is really only scratching the surface of how versatile and solid the new routing solution will be. Any thoughts?

Reverse Routing Just to finish this off lets take a look at what really tidies all this up into a neat package: Reverse routing. This allows us to generate application links using our configured routes set-up. For instance:

echo router::uri('blog_post', array(
    'year' => '1983',
    'month' => '08',
    'day' => '22')
);

The above will now happily generate the route post/1983/08/22. On its own not to fantastic, and it came at the price of a slightly longer link generation syntax. However as some of you are probably realising if we ship this app over to the states where they do everything backwards ( :) ) we now want to switch our urls to read ‘post/:year/:day/:month’, so by making that ONE change in our routes config every single one of our application links will now match this backwards way of doing things, and because we retrieve our url arguments by name none of our code will be affected . . truly awsome. Reorganising methods and controllers is no longer an issue either. Play around with it and see what you think. Hopefully you will be impressed!

Breath – That turned out to be a bit longer than anticipated so hopefully you got all the way through it, as usual any problems, glaring omissions then please don’t hesitate to drop me a line! /Matt