These forums are read-only and for archival purposes only!
Please join our new forums at discourse.kohanaframework.org
[SOLVED] Hyphens (-) to underscores (_) with lambda routes? [3.1]
  • I would like to have URLs like

    http://localhost/staticcontroller/dynamic-actions-with-hypens

    In version 3.0.x I could extend Kohana_Request to achieve desired result

    request.php

    <?php defined('SYSPATH') or die('No direct script access.');
    
    class Request extends Kohana_Request
    {
        public function execute()
        {
            $this->action = str_replace('-', '_', $this->action);
            return parent::execute();
        }
    }
    

    How could I achieve same result with Kohana version 3.1 ?

    Is lambda routes solution for this? Is there a good example how to do this?

  • One working solution is:

    route.php

    <?php defined('SYSPATH') OR die('No direct access allowed.');
    
    class Route extends Kohana_Route
    {
        public function matches($uri)
        {
            $matches = parent::matches($uri);
            if (isset($matches['action']))
            {
                $matches['action'] = str_replace('-', '_', $matches['action']);
            }
            return $matches;
        }
    }
    

    But is there better way to do this?

  • I use this..

    class Request extends Kohana_Request
    {
        public function __construct($uri)
        {
            parent::__construct($uri);
    
            $this->_controller = str_replace('-', '_', $this->_controller);
            $this->_action = str_replace('-', '_', $this->_action); 
        }
    }
    
  • Dynamic actions? What does that mean?

    If the actions come from a database you can fetch them and create routes for those actions.

    foreach($model->actions() as $action)
    {
        Route::set('hypens-'.$action,'staticcontroller/'.$action)
        ->defaults(array(
               'controller'=>'staticcontroller',
               'action'=>str_replace('-','_',$action),
        ));
    }
    
  • @xwero I meant that action-part of uri is changing and the controller part stays static

    eg.

    http://localhost/ctrl/differentaction

    http://localhost/ctrl/someaction

    http://localhost/ctrl/anotheraction

    @nickobrien Wouldn't it be better extend Kohana_Route than Kohana_Request ?

  • The reason I asked is when I see dynamic I think variables, fetched from elsewhere, generated.

    I think your getting too soon in the 'extend framework' mindset while the framework has a solution for this problem, routes. You suggested it's only for that controller so you let the exception become the rule.

    Can you give a real world example of the actions you use hypens in. I'm wondering if you couldn't write them as action/parameter.

  • If you have to do this using a string substitution, ensure that the uri using _ is invalid, otherwise you'll have two valid URL's able to reach the same resource- bad. Bad. BAD!!!

    Personally, as @xwero said, this is a solved problem using well defined Routes instead of hacks.

  • @samsoir I'll ensure that there isn't double content via 301 Moved Permanently -redirects.

    @xwero

    Can you give a real world example of the actions you use hypens in. I'm wondering if you couldn't write them as action/parameter.

    I'm quite sure this is possible to route with lambda routes, I just don't know how to do it.

    Here's example...

    Route

    Route::set('test', 'test/<action>', array(
        'action'        => '([a-z\-]+)',
    ))
    ->defaults(array(
        'controller'    => 'test',
        'action'        => 'method_one',
    ));
    

    Controller

    class Controller_Test extends Controller {
    
        public function action_method_one()
        {
            /* ... */
        }
    
        public function action_method_two()
        {
            /* ... */
        }
    
        public function action_method_three()
        {
            /* ... */
        }
    }
    

    URLs

    http://localhost/test/method-one
    http://localhost/test/method-two
    http://localhost/test/method-three
    
  • I'm quite sure this is possible to route with lambda routes, I just don't know how to do it.

    Pretty simply;

    Route::set('test', function ($uri) {
        if (list($controller, $action) = explode('/', $uri, 2) AND $controller === 'test')
        {
            return array(
                'controller'  => $controller,
                'action'      => str_replace('-', '_', $action)
            )
        }
     },
     'test/<action>');
    
  • I tried your solution Samsoir but it gives me 2 valid URL's that can access one page - one with "-" and one with "_"

  • @matino, I wasn't handling the duplicate endpoint situation with the example above. Amended version below.

    Route::set('test', function ($uri) {
       if (list($controller, $action) = explode('/', $uri, 2) AND $controller === 'test' AND strpos($action, '_') === FALSE)
       {
           return array(
               'controller'  => $controller,
               'action'      => str_replace('-', '_', $action)
           )
       }
    },
    'test/<action>');
    
  • I would even go a step further.

    Route::set('test', function ($uri) {
      $actions = array('method-one','method-two','method-three');
      list($controller, $action) = explode('/', $uri, 2);
    
      if ($controller === 'test' AND in_array($action,$actions))
       {
           return array(
               'controller'  => $controller,
               'action'      => str_replace('-', '_', $action)
           )
       }
    },
    'test/<action>');
    
  • @xwero, that's perfectly valid to do in the route, but the Request_Client would also return a 404 if the $action is not in the controller.

  • @samsoir of course there is a method check, my reasoning is void. I removed it.

  • First of all thanks to samsoir for sharing!
    Below my tweaked version:
    - underscore is replaced in both controller and action
    - default controller and action is set
    - allow only fixed controllers
    Route::set('modules', function ($uri) { @list($controller, $action) = explode('/', $uri, 2);

        // Disbaled 2 valid URL's to the same recourse
        if (strpos($controller . $action, '_'))
            return;
    
        // Set default values for action and controller
        if (empty($controller))
        {
            $controller = 'index';
        }
        if (empty($action))
        {
            $action = 'home';
        }
    
        // Only accept below controllers
        $controllers = array('controller1', 'controller2', 'index');
        if (in_array($controller, $controllers))
        {
            return array(
                'controller'  => str_replace('-', '_', $controller),
                'action'      => str_replace('-', '_', $action)
            );
        }
    },
    '<controller>(/<action>(/<id>))');
    

  • @martino the controllers don't need the hypen to underscore code as there is no hypen in them.

  • Thanks everyone, this solved the problem!

  • @matino, you're using error suppression @ on list(). Error suppression is is evil and should be avoided at all cost. PHP will issue a notice if list() cannot handle what is assigned to it, which is recoverable in a try/catch block.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion