CakePHP introduces a new way of writing your routes, you can now restrict your URLs at parameter level, meaning that we can now specify URLS like /date/:year/:month instead of /date/*. This post compares CakePHP 1.1 and 1.2 routing differences. I’ll start with showing the old way first:

CakePHP 1.1 way

In CakePHP 1.1, routings looks like this in /app/config/routes.php:

[code lang=“php”]Router->connect(‘/date/*‘, array(‘controller’ => ‘posts’, ‘action’ => ‘p_date’));[/code]

And the corresponding method in the controller would look something like this:

[code lang=“php”]

function p_date($year, $month) {

$posts = $this->Post->findAll(

“MONTH(pub_date)=$month AND YEAR(pub_date)=$year”

);

$this->set(‘posts’, $posts);

}

[/code]

CakePHP 1.2 way

There isn’t much changes in CakePHP 1.2’s routing handling statement except that now it uses 2 colons.

[code lang=“php”]Router::connect(‘/date/*‘, array(‘controller’ => ‘posts’, ‘action’ => ‘p_date’));[/code]

No change in the controller’s method.

[code lang=“php”]

function p_date($year, $month) {

$posts = $this->Post->findAll(

“MONTH(pub_date)=$month AND YEAR(pub_date)=$year”

);

$this->set(‘posts’, $posts);

}

[/code]

But what if there’s a need for constricting the user to only certain years and months at URL level. I don’t know about you, but I don’t have posts in year 1954. I don’t want people passing invalid arguments into URLs too. You can pass the following URLs:

  • /date/2008/3/
  • /date/whatever/122211/
  • /date/1954/20/

The above examples are all valid routes but the database don’t have a valid match. So we can try do stricter routings in CakePHP 1.2.

[ad#highlight]

CakePHP 1.2 ‘stricter’ way

In /app/config/routes.php of CakePHP 1.2:

[code lang=“php”]

Router::connect(‘/date/:year/:month’, array(‘controller’ => ‘posts’, ‘action’ => ‘p_date’), array(‘year’ => ‘[2][0-9]{3}‘, ‘month’ => ‘([1-9]|1[012])‘));

[/code]

The year field would match any year from 2000 to 2999 inclusive. The month field would match any months 1 to 9 or 10, 11 and 12. That should cover all the months. This is how your method would look like:

[code lang=“php”]

function p_date() {

$year = $this->params[‘year’];

$month = $this->params[‘month’];

$posts = $this->Post->findAll(

“MONTH(pub_date)=$month AND YEAR(pub_date)=$year”

);

$this->set(‘posts’, $posts);

}

[/code]

Note that now p_date() method doesn’t take any arguments, instead you retrieve the URL using $this->params[‘year’]. If users try to access an invalid URL, the user will get some 404 page. And since the URL is invalid, the method will not be invoked, this saves the database from being called unnecessarily.

I like it that the preg_match is now done at the Router instead of in the method itself. It makes things a lot neater in the long run.

comments powered by Disqus