Plankje
Plankje

Reputation: 298

Kohana 3.2 routing rewrite action

I have a uri scheme which is like <country>/<id>_<action>/<name> which descends from an old site and I am porting the site to the Kohana framewerk. A possible URL is http://www.example.com/us/1234_1/foo

The value of <action> is a digit from 0 to 9: \d. Every digit refers to a action, e.g. 0 is overview.

How can I set my routing in the bootstrap, with the requested action ported correctly.

This is what I have now, but obviously it does not behave correctly, because it tries to call the function Action_0 instead of Action_Overview, given the example url:

Route::set('default'), '<country>/<id>_<action>/<name>')
     ->defaults(array(
        'controller' => 'index',
        'action'     => 'index'
     ));

Upvotes: 0

Views: 876

Answers (2)

zrvan
zrvan

Reputation: 7753

It would of course be nice with a clean solution, but I'm afraid there isn't one available. I can think of a few ways to handle it, none of them, however, ideal.

No 1. Would be the subrouter idea provided by Darsstar

No 2. Would be similar to solution no. 1, but use a dual route system, along the lines of:

Route::set('default'), '<country>/<id>/<action>/<name>', array ('country' => '.+', 'name' => '.+', )) /* new */
 ->defaults(array(
    'controller' => 'new',
    'action'     => 'index'
 ));

and

Route::set('legacy'), '<country>/<id>_<oldaction>/<name>', array ('country' => '.+', 'name' => '.+', 'oldaction' => '\d+', )) /* legacy */
 ->defaults(array(
    'controller' => 'legacy',
    'action'     => 'route'
 ));

The new controller would use action_overview() etc. to your liking and the legacy would hold only one action, action_route() doing something like this:

public function action_route ()
{
  $actions = array (0 => 'overview', ...);

  $params = array (
    'country' => $this->request->param ('country'),
    'id' => $this->request->param ('id'),
    'action' => $actions[$this->request->param ('oldaction')],
    'name' => $this->request->param ('name'),
  );
  $this->request->redirect (Route::get ('legacy')->uri ($params));
}

No 3. Would be to simply use multiple routes, if the number of actions aren't that great, consider using one route per action like this:

Route::set('overview'), '<country>/<id>_0/<name>')
 ->defaults(array(
    'controller' => 'index',
    'action'     => 'overview'
 ));

Route::set('details'), '<country>/<id>_1/<name>')
 ->defaults(array(
    'controller' => 'index',
    'action'     => 'details'
 ));

You could make this a bit more manageable by using a foreach() along the lines of this:

$actions = array (
  'overview',
  'details',
);
foreach ($actions as $idx => $action)
{
  Route::set($action), '<country>/<id>_' . $idx . '/<name>')
    ->defaults(array(
      'controller' => 'index',
      'action'     => $action,
   ));
}

When this is done, you can use a controller with action action_overview(). In production, use caching for the routes to avoid redefining them on each request.

Personally I would opt for no 3 if it's a straight port and there's no plans for extending the site with new functionality. Otherwise I'd go with no 2, because it allows for a legacy mode that can be phased out over time. Also, it allows for more flexible "new" routes.
I would not choose no 1 only because it's -- in my mind -- not in keeping with the Kohana style of coding, I would personally expect to find routing rules either in bootstrap.php or init.php (in the case of modules). It's a perfectly valid solution otherwise (and in a sense it is in the style of Kohana, in that Kohana is flexible enough to allow for solutions that goes against it's general style... :) )

Upvotes: 0

Darsstar
Darsstar

Reputation: 1895

One solution would be to name the actions action_0 to action_9, but I either of us likes that.

Another solution would be to 'reroute' the action in Controller::before() like this:

public function before()
{
    parent::before();

    $actions = array(0 => 'overview', ...);

    $this->request->action($actions[$this->request->action()]);
}

Or you could do that in a lambda/callback route, but I would keep it in Controller::before().

Upvotes: 2

Related Questions