0
votes

I have a route as:

((?<directory>\w+)/?)?((?<controller>\w+)/?)?((?<action>\w+)/?)?((?<id>\d+))?

It works fine but it causes my system to have to include the default controller (index) for all routes to the sub routes. For example, if my page URI is /blog/post (where blog is the directory and post would be the action), my actual URI would have to be blog/index/post - I'd like to be able to fall back to just using blog/post instead.

So, I would like it to be routed to:

directory = blog
controller = index
action = post

Obviously this causes issues when the second parameter is actually a controller. For example directory/controller/action would be routed incorrectly.

Is there a routing method to detect that there are three word parameters, possibly followed by a numeric parameter, which can do what I need?

For claification:

  • param/param/param(?/id) would be: directory/controller/action(/id)
  • param/param(?/id) would be: directory/default_controller/action(/id)
2

2 Answers

3
votes

i'd actually think that you want to alias blog/index/post with blog/post; insert it as a route before the "catch-all" route that you have; the "one big shoe fits all" approach is not always the best. Especially, if you only have 1 such particular use case.

edit:

"kohana's routing system" is daunting; can't make sense of the elephant they're trying to give birth to there... here are some other suggestions:

  1. Take this issue to the manufacturer; this is definetely an FAQ question
  2. Mess around with the regex patterns. Here's a snippet that might be useful (i put it inside a PHP test case, but you could easily decouple it)

    public function testRoutePatterns(){
        $data = array(
        array(
            //most specific: word/word/word/id
            '~^(?P<directory>\w+)/(?P<controller>\w+)/(?P<action>\w+)/(?P<id>.*)$~i', 
            'myModule/blog/post/some-id',
            array('directory'=>'myModule', 'controller'=>'blog', 'action'=>'post', 'id'=>'some-id'), 
            true
        ),
        array(
            //less specific: word/word/id
            '~^(?P<directory>\w+)/(?P<action>\w+)/(?P<id>.*)$~i', 
            'blog/post/some-id',
            array('directory'=>'blog', 'action'=>'post'), //need to inject "index" controller via "defaults()" here i guess
            true
        ),
        );
    foreach ($data as $d) {
        $matches = array();
        list($pattern, $subject, $expected, $bool) = $d;
        $actual = (bool) preg_match($pattern, $subject, $matches);
        $this->assertEquals($bool, $actual); //assert matching
        $this->assertEquals(array(), array_diff($expected, $matches)); //$expected contained in $matches
     }
    }
    
0
votes

As explained on this answer, if you have some route like this:

Route::set('route_name', 'directory/controller/action')
    ->defaults(array(
        'directory'  => 'biz',
        'controller' => 'foo',
        'action'     => 'bar',
    ));

You should have the directory structure like this:

/application/classes/controller/biz/foo.php