We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Router: How to force "/:controller/:action/:params" to match "/controller" (without action)

I have tried to make route like this: "/forum/:controller/:action/:params". Just to separate forum from other controllers by using different namsepace. But I have noticed that this pattern matches only strings like "/forum/controller/action" or "/forum/controller/action/params", but not "/forum/controller" and "/forum". I thought that missing part are replaced with default ones. I even try to assign defaults by hand.

How to make universally route for "/sothething", "/sothething/controller", "/sothething/controller/action", "/sothething/controller/action/params" altogether? Only thing I want is to add some subpath after domain name and use usual behaviour for match uri after this subpath.



98.9k

You need at least two routes to achieve the desired behavior:

$router->add("/forum/:controller/:action/:params", array(
    'controller' => 1,
    'action' => 2,
    'params' => 3
));

$router->add("/forum/:controller", array(
    'controller' => 1   
));


32.5k

Nope, the last one route you have posted doesn't match simple "/forum". And that is the proplem. I don't want to make 2 extra routes for each such case.

When the params hadn't matched then it doesn't putted into dispatcher. But why the controller and action do? When I try to make universal pattern than unmatched groups puted as is (1 or 2) and I get something like "action '2' not found".



98.9k

I think is not easy create an "universal" route, you can add a third route to match only /forum:

$router->add("/forum", array(
  'controller' => 'index'  
));

You can try to find a regular expression that universally matches the desired pattern but it would look very complex and less flexible:

$router = new Phalcon\Mvc\Router(false);

//Matches /forum and /forum/controller
$router->add('/forum([/]{0,1})([a-zA-Z]+){0,1}', array(
        'controller' => 2
));

$router->handle('/forum/x');

var_dump($router->getMatchedRoute());
var_dump($router->getControllerName());


32.5k
edited Oct '14

I have found it. Something like:

/forum(?:/)?([a-zA-Z0-9_-]+)?(?:/)?([a-zA-Z0-9_-]+)?(?:/)?(.+)*

The problem is that, for example, for this:

$router->add('/forum([/]{0,1})([a-zA-Z]+){0,1}', array(
        'controller' => 2
));

for the uri "/forum" the server warns me with this:

Warning: Phalcon\Dispatcher::dispatch(): Invalid arguments supplied for memnstr() 
Warning: Phalcon\Dispatcher::dispatch(): Invalid arguments supplied for camelize() 


98.9k

Yep, since some patterns are optionally matched the paths aren't filled passing incorrect values to the dispatcher



32.5k

Can I expect that this behavior will be changed? (May I create an issue for this on github?)

I thing the logical and right behavior of router is to use default controller/action/etc. if ones are missed. Because the $router->setDefaults() seems some useless against the problem of the current discussion =)

Anyway, creation of flexible routes is a good possibility.



98.9k

This pattern works as expected:

$router->add('/forum/?{controller:[\w\-]+}/?{action:[\w\-]*}{params:/?.*}');

Or:

$router->add('#^/forum/?([\\w\\-]+)/?([\\w\\-]*)(/?.*)$#',  array(
        'controller' => 1,
        'action' => 2,
        'params' => 3,
));


32.5k

Hmmm... I think I understood at last how router deals with regexp =) With '*' instead of '+' in controller group even '/forum' is dispatched correctly. Thanks a lot, that's exactly, exactly what I was looking for! Short, simple and working.