views:

46

answers:

1

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?

+2  A: 

/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. :)

deceze
I've been reading up on routes, however, as a newcomer to Cake, the connection between many of the components isn't always obvious. Cake does a lot of magic up-front which has left me wondering how exactly it's doing what it's doing when I need to move outside the conventions.(I am reading the cookbook, but I can only read so quickly)
Soviut
@Soviut Yeah, it's a pretty complex topic, until you get it. Added some more explanation about the magic, hope that helps.
deceze
Thanks. You got my vote and my accept! I just wish the Cake docs would show me the hard way to do everything, then show me the easy way after. Showing the easy way first tends to pacify people and then they get stuck when they need to do things outside the convention.
Soviut
@Soviut That's an interesting perspective, the Cake guys may indeed have a marketing problem there. It looks easy enough on the surface, and *once you get it* you can get things done quickly thanks to convention-over-configuration, by it may indeed be a bad idea to sell Cake as "easy" to newcomers. I think that's the same reason I hated "Why's poignant guide to Ruby".
deceze
+1 My issue with Cake's docs (and I've gotten some shit from the team for saying so) is that they usually illustrate the trivial case, but no alternatives--certainly nothing more complex. Real project scenarios are rarely so trivial.
Rob Wilkerson