Search code examples
urlcakephproutesconventions

How to create custom routes for certain actions in a CakePHP controller?


Coming from Django, I'm used to be able to organize my URL routings any way I see fit. For example, user registration would exist under the /users/ url.

/users/
/users/registration/
/users/registration/optin/
/users/registration/thankyou/

However, I'm creating a user registration system in CakePHP and the default convention behaviour for url routings is /controller/action/. This yields:

/users/
/users/registration/
/users/optin/
/users/thankyou/

How can I achieve a /controller/action/custom/ style-url routing on some of my actions (where /custom/ is a sub-section, not a parameter)? Should I even be expecting to do this or am I just fighting the convention?


Solution

  • /controller/action/custom/ works fine by default.
    It invokes ControllerController::action('custom').

    If you're looking for something like invoking UsersController::thankyou() through the URL /users/registration/thankyou, you can make an appropriate route:

    Router::connect('/users/registration/thankyou',
                    array('controller' => 'users', 'action' => 'thankyou'));
    

    You can group routes in one rule like this:

    // Routes /users/registration/optin and /users/registration/thankyou to
    // UsersController::optin() and UsersController::thankyou() respectively
    Router::connect('/users/registration/:action',
                    array('controller' => 'users'),
                    array('action' => '(optin|thankyou)'));
    

    Routes are very powerful and completely flexible in Cake. As always, study the manual:
    http://book.cakephp.org/view/945/Routes-Configuration


    The basics are that the Router matches the route, e.g. '/users/registration/:action', against the current URL, including conditions specified in the third parameter, e.g. 'action' => '(optin|thankyou)' (the :action part has to match the RegEx /^(optin|thankyou)$/).
    If it matches, it merges the defaults from the second parameter with any information extracted from the URL, so you get array('controller' => 'users', 'action' => 'thankyou') for example.
    It then pushes it through CakeRoute::parse, which constructs the array you can see when doing debug($this->params) in a controller. This array is used to figure out which Controller to load and which action to invoke.

    The basic RegEx and parameter matching is already very powerful, but you can go completely crazy by subclassing CakeRoute and providing a custom parse function, as briefly explained at the end of the manual. :)