8 min read

 

(For more resources on this topic, see here.)

The reader can benefit from the previous article on Request Flow in Kohana 3.

Routing in Kohana

If you remember, the bootstrap file comes preconfigured with a default route that follows a very simple structure:

Route::set(‘default’, ‘(<controller>(/<action>(/<id>)))’)
->defaults(array(
‘controller’ => ‘welcome’,
‘action’ => ‘index’,
));

This tells Kohana that when it parses the URL for any request, it first finds the base_url, and then the next segment will contain the controller, then the action, then an ID. These are all optional setgments, with the default controller and action being set in the array. We have taken advantage of this route with other controllers like our Profile and Message controller.

When we visit http://localhost/egotist/profile, the route sets the controller to profile, and since no action or ID is explicitly defined in the URL, the default action of ‘index’ is used. When we requested http://localhost/egotist/messages/get_messages from within our Profile Controller, we also followed this route; however, neither defaults were needed, and the route asked for the Messages Controller and its get_messages action.

In our Profile controller, we are only using one array of example messages to test functionality and the expected behavior of our application. When we implement a data store and have multiple users with profiles in our application, we will need a way to decipher which profile a user wants to see.

Because the default route already has an available parameter for ID, we can use that to pass an ID to our Profile Controller’s index action, and have the messages controller then find the proper messages for that user.

 

Time for action – Making profiles dynamic using ID

Once a database is tied to our application, and more than one user has a profile, we will need some way of knowing which profile to display. A simple and effective way to do this is to pass a user ID in the route, and have our controller use that ID to find the right messages for the right user. Let’s add some more test data to our messages system, and use an ID to display the right messages.

  1. Open the Profile Controller in our application/classes/controller/ directory named profile.php. Since the action_index() method is the controller action that is called when a profile is viewed, we will need to edit it to look for the ID parameter in the URI like this:

    public function action_index()
    {
    $content = View::factory(<profile/public>)
    ->set(<username>, <Test User>)
    ->bind(<messages>, $messages);
    $id = (int) $this->request->param(‘id’);
    $messages_uri = "messages/get_messages/$id";
    $messages = Request::factory($messages_uri)->execute()-
    >response;
    $this->template->content = $content;
    }

  2. Now, we are retrieving the ID from the route and passing it along in our request to the Messages Controller. This means that class must also be updated. Open the messages.php file located in application/classes/controllers/ and modify its action_get_messages() method as follows:

    public function action_get_messages()
    {
    $id = (int) $this->request->param(‘id’);
    $messages = array(
    1 => array(
    ‘This is test message one for user 1’,
    ‘This is test message two for user 1’,
    ‘This is test message three for user 1’
    ),
    2 => array(
    ‘This is test message one for user 2’,
    ‘This is test message two for user 2’,
    ‘This is test message three for user 2’
    )
    );
    $messages = array_key_exists($id, $messages) ? $messages[$id] :
    NULL;
    $this->request->response = View::factory(‘profile/messages’)
    ->set(‘messages’, $messages);
    }

  3. Open the page http://localhost/egotist/profile/index/2/. It should look like this:

    Kohana 3.0,Beginner's Guide

    Browsing to http://localhost/egotist/profile/index/1/ will show the messages for user 1, i.e., the test messages placed in the message array under key 1.

What just happened?

At the very beginning of our index action in our Profile Controller, we set our $id variable by getting the ID parameter from the route. Since Kohana has parsed our route for us, we can now access these parameters via the request object’s param() method.

Once we got the ID variable, we then created and executed the request for the message controller’s get_messages action, and passed the ID to that method for it to use.

In the Message Controller, we used the same method to extract the ID from the request, and then used that ID to determine which messages from the messages array to display. Although this works fine for illustrating routing for these two users, the code is far from ready, even without a data store or real user data, but it does show how the parameters can be read and used.

Because most of the functionality in the controller will be replaced with our database and more precise data being passed around, we can overlook the incompleteness of the current controller actions, and begin looking at creating a URL that is better looking than http://localhost/egotist/profile/index/2/ for finding a user profile by ID.

Creating friendly URLs using custom routes

Consider how nice it would be if our users could browse to a profile without putting ‘index’ in the action portion of the URI, like this: http://localhost/egotist/profile/2. This looks much more pleasing, and is more in line with what we would like our URLs to look like in web apps. It is in fact very easy to have Kohana use a route to remove the index action from the URI.

Routes not only make our URLs more pleasing and descriptive, but they make our application easier to maintain in the long run. We have more control over where our users are being directed from how the URL is constructed, without having to create controller actions designed to handle routing.

 

Time for action – Creating a Custom Route

So far, we have been using the default route that is in our application bootstrap. As our application grows, so will the number of available ‘starting points’ for our user’s requests. Not every controller, action, or parameter has to comply with the default route, and this gives us a lot of flexibility and freedom.

We can add a custom route to handle user’s profiles by adding it to our bootstrap.php file.

  1. Open the bootstrap.php file located in application/directory and modify the routes block so it looks like this:

    /**
    * Set the routes.Each route must have a minimum of a name,a URI
    * and a set of defaults for the URI.
    */

    Route::set(‘profile’, ‘profile/<id>’)
    ->defaults(array(
    ‘controller’ => ‘profile’,
    ‘action’ => ‘index’,
    ));
    Route::set(‘default’, ‘(<controller>(/<action>(/<id>)))’)
    ->defaults(array(
    ‘controller’ => ‘welcome’,
    ‘action’ => ‘index’,
    ));

  2. Now, we can view the profile pages without having to pass the index action in the URL. Open http://localhost/egotist/profile/2 in a browser; it should look like this:

    Kohana 3.0,Beginner's Guide

  3. Browsing to profiles with a more friendly URL is made possible through Kohana’s routes.

What just happened?

By setting routes using the Route::set static method, we are essentially creating filters that will be used to match requests with routes. We can name these routes; in this case we have one named default, and one named profile. Kohana uses the second parameter in the set() method to compare against the requested URI, and will call the first route that matches the request. Because it uses the first route that matches the request, it is very important when ordering route definitions. If we put the default route before the profile route, the profile route will never be used, as the default route would always match first.

Because it looks for a match, it does not use discretion when determining the right route for a request. So if we browse to http://localhost/egotist/profile/index/2, we will be directed to the default route, and get the same result. The default route may not be available for all the routes we create in the future, so create routes that are as explicit as we can for our needs.

Right now, our application assumes any data that is passed after a controller segment named ‘profile’ must be the ID for which we are looking. In our current application setup, we only need digits. If a user passes data into the URL that is not numeric for the ID parameter, we do not want it to go to that route. This can be accomplished easily inside the Route::set() method.

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here