Skip to content

DrF Reverse Routing

World Wide Web Server edited this page Jul 4, 2012 · 29 revisions

DrF Reverse Routing is an extension of the URL Helper that overrides the site_url function to provide a reverse lookup. If a custom route can be found that matches the given "standard CodeIgniter URI", a custom route URI will be created and returned. Otherwise, a standard site_url will be returned.

[url=http://codeigniter.com/forums/viewthread/80283/]Discuss this in the Forum[/url]

[h2]Overview[/h2]

  • Translates a "standard CodeIgniter URI" into a custom route if possible. Standard, in this case, means [em]controller/function/param1/param2/.../paramN[/em]
  • Fails gracefully, providing a standard site_url if no route can be found/translated
  • Works automatically with all of URL Helper's functions
  • Concept inspired by CakePHP's reverse routing

[h2]Usage[/h2]

  • place MY_url_helper.php in your system/application/helpers folder
  • include the URL helper in your controller [code]$this->load->helper( 'url' );[/code]
  • use URL Helper's functions as you normally would

[h2]Example[/h2]

  • setup a Test Controller [code] <?php class Test extends Controller{

    function Test() { parent::Controller(); }

    function testFunc( $param1 ){ echo 'You passed in: ' . $param1; }

    function redirect() { $this->load->helper( 'url' ); redirect( 'test/testFunc/bar' ); }

} ?> [/code]

[h2]Download[/h2] File:DrF_Reverse_Routing.zip

[h2]Code[/h2] system/application/helpers/MY_url_helper.php [code] <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**

// ------------------------------------------------------------------------

/**

  • (Reverse) Site_URL

  • Returns a custom routed URL if one exists. Returns a normal site_url otherwise.

  • It works by translating the passed-in URI into a custom route URI, if possible.

  • This function does not handle ANY regex used without capture-groups and back-references.

  • Visit http://drfloob.com/codeIgniter/reverse_redirect to learn why

  • @access public

  • @param $uri The standard CI URL, e.g. controller/function/param1

  • @param $method

  • @param $http_response_code */

    function site_url($uri = '') { $Router =& load_class('Router');

     // $uri is expected to be a string, in the form of controller/function/param1
     // trim leading and trailing slashes, just in case
     $uri = trim($uri,'/');
     
     $routes = $Router->routes;
     $reverseRoutes = array_flip( $routes );
     
     unset( $routes['default_controller'], $routes['scaffolding_trigger'] );
     
     // Loop through all routes to check for back-references, then see if the 
     // user-supplied URI matches one 
     foreach ($routes as $key => $val)
     {
         // bailing if route contains ungrouped regex, otherwise this fails badly
         if( preg_match( '/[^\(][.+?{\:]/', $key ) )
             continue;
             
         // Do we have a back-reference?
         if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
         {
             // Find all back-references in custom route and CI route 
             preg_match_all( '/\(.+?\)/', $key, $keyRefs );
             preg_match_all( '/\$.+?/', $val, $valRefs );
             
             // Create URI Regex, to test passed-in uri against a custom route's CI
             // (standard) route.
             // Replaces back-references in CI route with custom route's regex 
             // [ $1 replaced with (:num), for example ].
             $uriRegex = $val;
             
             foreach( $valRefs as $tempKey => $ref )
             {
                 if( isset( $keyRefs[$tempKey] ) )
                     $uriRegex = str_replace( $ref, $keyRefs[$tempKey], $uriRegex );
             }
             
             // replace :any and :num with .+ and [0-9]+, respectively
             $uriRegex = str_replace(':any','.+',str_replace(':num','[0-9]+',$uriRegex));
             
             // regex creation is finished.  Test it against uri
             if (preg_match('#^'.$uriRegex.'$#', $uri))
             {
                 // A match was found.  We can now build the custom URI
                 
                 // We need to create a custom route back-referenced regex, to plug user's
                 // uri params into the new routed uri.
                 // First, find all custom route strings between capture groups
                 $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
    
                 $routeString = preg_split( '/\(.+?\)/', $key );
                 
                 // build regex using original CI route's back-references
                 $replacement = '';
                 $rsEnd = count( $routeString ) - 1;
                 
                 // merge route strings with original back-references, 1-for-1
                 for( $i = 0; $i < $rsEnd; $i++ ){
                     $replacement .= $routeString[$i] . $valRefs[0][$i];
                 }
                 $replacement .= $routeString[$rsEnd];
                 
                 /*
                     At this point,our variables are defined as:
                         $uriRegex:       regex to match against user-supplied URI
                         $replacement:    custom route regex, replacing capture-groups 
                                             with back-references
                             
                     All that's left to do is create the custom URI, and return the site_url
                 */
                 $customURI = preg_replace( '#^'.$uriRegex.'$#', $replacement, $uri );
                 
                 return normal_site_url( $customURI );
             }
         }
         // If there is a literal match AND no back-references are setup, and we are done
         else if($val == $uri)
             return normal_site_url( $key );
     }
     
     return normal_site_url( $uri );
    

    }

    function normal_site_url($uri = '') { $CI =& get_instance(); return $CI->config->site_url($uri); }

?> [/code]

Clone this wiki locally