CakePHP route with regex

2019-07-07 10:54发布

问题:

I have a controller setup to accept two vars: /clients/view/var1/var2

And I want to show it as /var1/var2

SO i tried

Router::connect('/*', array('admin'=>false, 'controller' => 'clients', 'action' => 'view'));

But this stops all other controllers working as /* routes everything

All other pages that are on the site are within the admin prefix so basically i need a route that is ignored if the current prefix is admin! I tried this (regex is from Regular expression to match a line that doesn't contain a word?):

Router::connect('/:one', array('admin'=>false, 'controller' => 'clients', 'action' => 'view'), array(
    'one' => '^((?!admin).*)$'
));

But I think the regex is incorrect because if i naviate to /test it asks for the tests controller, not clients

My only other routes are:

Router::connect('/admin', array('admin'=>true, 'controller' => 'clients', 'action' => 'index'));
Router::connect('/', array('admin'=>false, 'controller' => 'users', 'action' => 'login'));

What am I doing wrong? Thanks.

回答1:

I misunderstood your question the first time. I tested your code and didn't get the expected result either. The reason might be that the regex parser doesn't support negative lookahead assertion. But I still think you can solve this with reordering the routes:

The CakeBook describes which routes are automatically generated if you use prefix routing. In your case these routes have to be assigned manually before the '/*'-route to catch all admin actions. Here is the code that worked for me:

// the previously defined routes
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/admin', array('controller' => 'clients', 'action' => 'index', 'admin' => true));

// prefix routing default routes with admin prefix
Router::connect("/admin/:controller", array('action' => 'index', 'prefix' => 'admin', 'admin' => true));
Router::connect("/admin/:controller/:action/*", array('prefix' => 'admin', 'admin' => true));   

// the 'handle all the rest' route, without regex
Router::connect(
    '/*', 
    array('admin'=>false, 'controller' => 'clients', 'action' => 'view'), 
    array()
);

Now I get all my admin controller actions with the admin prefix and /test1/test2 gets redirected to the client controller.



回答2:

I think the solution is described in the bakery article on routing - "Passing parameters to the action" (code not tested):

Router::connect(
    '/clients/view/:var1/:var2/*',  
    array( 
        'controller' => 'clients',
        'action' => 'view'
    ),
    array( 
        'pass' => array( 
            'var1', 
            'var2' 
        ) 
    ) 
);

The controller action would look like:

public function view($var1 = null, $var2 = null) { 
    // do controller stuff
}

Also you have too look at the order of your routes (read section "The order of the routes matters"). In your example the '/*' stops all other routes if it comes first, if you assign the rule after the others it handles only requests which didn't match any other route.