Respect/Rest

Plural or multiple paths to same routine

Closed this issue · 7 comments

Hey guys. Wondering if there's already something for this that I'm overlooking. For times when you have the singular and pluralizes paths take the same action, is there a way of combing these in one call? Currently I declare the routine as a function then make two separate path declarations. I'd love to do something like this:

    $router->get(array('/User','/Users'), function ()......);

I do not think this is possible currently but +1 for very useful idea indeed.

@blindsamson what you are suggesting is probably going to be the easiest route to market. You can roll a pull request with the following suggestion if you like, to bring it under review.

Modifying the router as follows should do the trick (pending tho outcome from actually testing it):

/** ... snip imports **/

class Router
{
   /** ... snip other methods and properties  **/
    public function __call($method, $args)
    {
       /** .. snip Invalid argument check **/

        list ($path, $routeTarget) = $args;
// ------------------- Patch required
        // Support multiple route definitions as array of paths
        if (is_array($path)) {
            $lastPath = array_pop($path);
            foreach ($path as $p)
                 $this->$method($p, $routeTarget);
             return $this->$method($lastPath, $routeTarget);
        }
// ------------------- End Patch
        /** ... snip rest of Router.php **/
     }
}

Would that suffice?

But since this is not a rush for budget quick fix kind of project, perhaps we can consider something else which might be more complicating to accomplish but will be awesome. =)

This shouldn't discourage you to submit a pull request for the quick fix in the interim as what I am about to suggest is definitely not going to be a walk in the park.

Extending the path declaration syntax:

To allow wild card path definitions which are not parameters, we may consider something like:

  • /user*/load - for /user/load or /users/load or /user-anything-really/load
  • /user?/load - for /user/load or /users/load or any one valid uri path character as ?
    */user+/load - for /users/load or any one or more valid uri path character(s) as +
  • /*-user - similarly anything preceding
  • /crazy-*-path - or anything in between

This implicates AbstractRoute::createRegexPatterns which is tasked with creating the uri to route matching expression stored in class member regexForMatch and later accessed in the method match which employs PHP's preg_match for the task.

Impediments

As they relate to the current AbstractRoute::createRegexPatterns implementation:

  • already escapes preg
  • already has special meaning for *
  • already manufactures a rather complex regular expression as is
  • very likely more worms in can not yet evident

@Respect your thoughts?

My original idea was to do the array method as I suggested. When I was perusing the code to see how to implement this I saw the create regex method and had the same idea for including the regex in the path name. I'm wondering what y'all think is the better implementation here. The regex way could be less coding on the front end, but may add more complexity than needed.

I'm -1 for passing array in the first argument. It would be done easily without adding a new feature.

$user_route = function() {...};
$router->get('/User', $user_route);
$router->get('/Users', $user_route);

or

$user_route = $router->get('/User', function{...});
$router->get('/Users', function() use($user_route) {
    return $user_route;
});
// can I do this here???
// $router->get('/Users', $user_route);

or

$router->get('/User', 'UserController');
$router->get('/Users', 'UserController');

@blindsamson 's approach is really useful since it can be done with a single line. But I think keeping api minimal and simple is more important issue than a handy method.

My thoughts:

Our path declaration syntax is awesomely useful, but dead. In a good way. /* tokens are a nice shortcut for path segments, but RFC6570 is the way to go https://tools.ietf.org/html/rfc6570. We can implement it and still support the /* as an extension.

I did a port of Respect\Rest matching engine to JavaScript and extended the path syntax to support #fragment-identifiers but I don't think that applies here =) https://github.com/Aeronautics/Concorde

Anyway, I like the array idea. Not only for paths:

$router->get(['/foo', '/bar'], /* ... */);
$router->instanceRoute(['get', 'retrieve', 'mycustommethod'], ['/foo', '/bar'], /* ... */);

So, +1 for arrays as builders for multiple equivalent routes by method or path.

What do you guys think about the URI Templates RFC?

@smagch

I agree that API should be kept minimal, but I also think that we should look at how often the "workaround" would be used. I think that an API should allow the writer to write more elegant code and not force them to come up with something like that. It also is more in line with DRY.

Superseded by #90