• Archives

  • Categories

Apr 26

How to perform routing in CakePHP 1.2

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:

Router->connect(‘/date/*’, array(‘controller’ => ‘posts’, ‘action’ => ‘p_date’));

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

function p_date($year, $month) {
  $posts = $this->Post->findAll(
    "MONTH(pub_date)=$month AND YEAR(pub_date)=$year"
  );
  $this->set(‘posts’, $posts);
}

CakePHP 1.2 way

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

Router::connect(‘/date/*’, array(‘controller’ => ‘posts’, ‘action’ => ‘p_date’));

No change in the controller’s method.

function p_date($year, $month) {
  $posts = $this->Post->findAll(
    "MONTH(pub_date)=$month AND YEAR(pub_date)=$year"
  );
  $this->set(‘posts’, $posts);
}

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.

CakePHP 1.2 ‘stricter’ way

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

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

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:

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);
}

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.

Possibly related:

  1. How to select data with month and year in MySQL
  2. CakePHP’s built-in Pages Controller
  3. How to get the controller’s action name from the view
  4. How to do logging in CakePHP

“How to perform routing in CakePHP 1.2”
4 comments

  1. If you use the CakePHP version from the development branch you can simplify your example even more:

    Router::connect(‘/date/:year/:month’, array(‘controller’ => ‘posts’, ‘action’ => ‘p_date’), array(‘year’ => $Year, ‘month’ => $Month));

    Apr 26

  2. KahWee

    @Daniel Hofstetter: Nice tip! I have the development version actually and I haven’t realized that.

    Apr 27

  3. hi
    I want to do this
    http://localhost/cake/Users/1/
    trying with
    Router::connect(
    “/:controller/:id”,
    array(“action” => “view”, “[method]” => “GET”, ‘id’=>’:id’),
    array(‘id’ => ‘[0-9]+’)
    );

    but it does not pick id in view($id).
    any help plz?

    May 15

  4. Hi atta, I think what you wanted to do instead would be

    Router::connect(
            "/:controller/:id",
            array("action" => "view", "[method]" => "GET"),
            array("id" => "[0-9]+")
    );

    By specifying “id” => “:id”, it results in an infinite loop.

    May 15

Leave your comment.


WordPress powered and Django inspired.
Love and elephants come after.
RSS: Posts and comments.