Easy Reverse Routing with CodeIgniter

I really can’t stand hard-coding URLs in the views or controllers of my application — and I’m sure most other people can’t either. Here’s an extension for the CodeIgniter Router class that I wrote that gives you a nice way to write routes that are reversible and also have the ability to take parameters.

routes) == 1)
		{
			$this->_set_request($this->uri->segments);
			return;
		}

		// Turn the segment array into a URI string
		$uri = implode('/', $this->uri->segments);

		// Is there a literal match?  If so we're done
		if (isset($this->routes[$uri]))
		{
			$this->_set_request(explode('/', $this->routes[$uri][self::ARR_ROUTE_POS]));
			return;
		}

		// Loop through the route array looking for wild-cards
		foreach ($this->routes as $key => $val)
		{
			// Convert wild-cards to RegEx
            //echo "$key --> ";
			$key = preg_replace('/\:\w+/', '[\w\-_]+', $key);
            //echo "$key 
"; // Does the RegEx match? if (preg_match('#^'.$key.'$#', $uri)) { // Do we have a back-reference? if (strpos($val[self::ARR_ROUTE_POS], '$') !== FALSE AND strpos($key, '(') !== FALSE) { $val = preg_replace('#^'.$key.'$#', $val[self::ARR_ROUTE_POS], $uri); } $this->_set_request(explode('/', $val)); return; } } // If we got this far it means we didn't encounter a // matching route so we'll set the site default route $this->_set_request($this->uri->segments); } function _buildReverseRoutes() { $reverse_routes = array(); foreach($this->routes as $route => $info) { # If this is a default route or scaffolding key, ignore it if(!is_array($info)) continue; $name = $info[self::ARR_ROUTE_NAME_POS]; $reverse_routes[$name] = $route; } $this->_reverseRoutes = & $reverse_routes; } function reverseRoute($route_name, $args_keyval = array()) { if($this->_reverseRoutes === NULL) $this->_buildReverseRoutes(); if(!array_key_exists($route_name, $this->_reverseRoutes)) show_error("No reverse route found for '$route_name'"); $route = $this->_reverseRoutes[$route_name]; foreach($args_keyval as $key => $val) { $route = str_replace("(:$key)", $val, $route); } return $route; } }

Drop that into application/libraries, then rewrite your routes to look like this:

$route['users/(:username)']  = array('users/$1', 'user-homepage');
$route['companies/(:slug)']  = array('companies/$1', 'company-homepage');

Let me explain that.

CodeIgniter lets you use wildcards in your routes like (:any) or (:num). That’s no more with this extension. Basically, anything you put in (:[name]) format with be treated like (:any). That’s handy, and I’ll tell you why.

Once you rewrite you routes, you can now call a new method on the routing class when you need to, say, redirect the user to his homepage after login:

  # login was successful, and we now have a $user object
  $this->load->helper('url');
  redirect($this->router->reverseRoute('user-homepage', array('username' => $user->username));

The reverseRoute method takes two parameters: The route you want to send the use on, and any wildcards that you need to fill in the url. For the user-homepage route, there is a (:username) wildcard in the route. We can pass the appropriate fill-in for that wilcard with the second parameter with an associative key-value array.

A redirect to a company-homepage would look like:

  # ...
  redirect($this->router->reverseRoute('company-homepage', array('slug' => $company->slug));

Then in the future, if you feel like changing your routes, go no further than the routes file! Mucking around in views is a recipe for broken links.

This entry was posted in Uncategorized. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Pingback: links for 2010-09-23 | Digitalistic - Mashup or die trying

  • Pingback: Reactor Update | Web Resources Updates

  • Pingback: Reactor Update | DEEP IN PHP

  • Pingback: Reactor Update | deepinphp.com

  • Fernando

    Hello, very nice your approach, I’m trying to implement it in CI 2 and I figured out that in order to work it’s need you put the MY_Router.php in the application/core folder..

    I guess it would be better if you had explained how create a controller/method using this way and wich url to access it using this configurated route.. it’s just a suggestion.. :)

    In the end, good job, man!!
    Hug

  • bogdan

    Ditto with the commenter above. You could do with correcting the article to say this should be included in application/core, not application/libraries.

    Otherwise, great resource, thanks!

  • Pingback: Easy Reverse Routing with CodeIgniter « Niroze's Weblog

  • http://www.blender-materials.com BlenderMats

    Thanks for this library.

    I suggest to replace in reverseRoute method “return $route;” with “return site_url($route)”;I had troubles where (:[name]) pattern is the first part of the rule.

    Bye

  • http://www.facebook.com/pkocanda Philip Kocanda

    Going to try this out right now. Looks pretty good!

  • Ruben Barilani

    Thx for the library. I know this it’s an old post but you have found also a locale routing strategy with this approach? I think something like Symfony Routing…

  • A H Abid

    This is really awesome stuff…. Thanks :)

  • Brewal Renault

    I have provided a fix on stackoverflow to handle regex parts of the route (not only wildcards) : http://stackoverflow.com/questions/26929288/reverse-routing-from-regex/26933155#26933155