phprouteskohana

Kohana module route precedence


I'm creating a Kohana module, and creating a route dynamically within that module. I'd like the route to take precedence over routes in the rest of the app. (Especially of the default, catch-all route).

Any thoughts on how to do this?

Thanks!

====== Update:

I think I forgot to mention that I'm loading the module dynamically, like this:

Kohana::modules(array_merge(array($module_name=>$directory), Kohana::modules()));

and then I'm running an HMVC request for the module, like so:

$response = Request::factory('versioned-api')
            ->method('POST')
            ->secure(true)
            ->post(array('data'=>serialize($request))) // Performing a straightforward POST
            ->execute();

Solution

  • Some background on Kohana (as of 3.2) module and routing precedence:

    1. Modules are initialized in the order Kohana::modules is called. This is important based on the desired precedence for routes. In your example, Kohana::modules(array_merge(array($module_name=>$directory), Kohana::modules()));, any modules already placed in Kohana::modules() have already been initialized. Even though you are merging a new module to the beginning of the list, modules are initialized as Kohana::modules() is called. If you look at "system/classes/kohana/core.php" line 565, you will notice that "init.php" is required once (if present in the module).
    2. Routes are matched in the order they are added. They are also overwritten if the same route name is used.

    In summary, there is no way natively in Kohana to push a Route to the beginning of the list. Of course, guaranteeing that the module in question is loaded first would solve your problem (as long as the route is not overwritten later on). If you can transparently extend Route, below is how you can accomplish this if the module is loaded later on by prepending the route to the beginning of the stack:

    GitHub Gist (including unit test): https://gist.github.com/3148737

    <?php defined('SYSPATH') or die('No direct script access.');
    /**
     * Route transparently extended. Place in "classes" directory of Kohana 3+ application or module.
     */
    class Route extends Kohana_Route
    {
        /**
         * Prepend Route to beginning of stack. If name already exists further in the stack, it is 
         * removed.
         * 
         *  Route::prepend('default', '(<controller>(/<action>(/<id>)))')
         *      ->defaults(array(
         *          'controller' => 'welcome'
         *      ));
         * 
         * @static
         * @access  public
         * @param   string   route name
         * @param   string   URI pattern
         * @param   array    regex patterns for route keys
         * @return  Route
         */
        public static function prepend($name, $uri_callback = NULL, $regex = NULL)
        {
            // Ensure entry does not already exist so it can be added to the beginning of the stack
            if (isset(Route::$_routes[$name]))
            {
                unset(Route::$_routes[$name]);
            }
    
            // Create reference
            Route::$_routes = array_merge(array($name => NULL), Route::$_routes);
    
            // Overwrite reference
            return Route::$_routes[$name] = new Route($uri_callback, $regex);
        }
    }