Cakephp routing: prefixes and forms

Prefixes are a nice way to define routes for groups of actions, (see the cookbook).

All admin_ actions go with the /admin// url
For my project i needed both an admin route and a dashboard route, so i made prefixes for them like:

(/app/config/routes.php)

Router::connect('/dashboard/:controller/:action/*', array('prefix' => 'dashboard'));

Now in the view you can use the following:

echo $html->link('Profile', array('controller'=>'users', 'action'=>'dashboard_profile'), array('title'=>'Edit profile'))

But when it comes to forms things start to break.

For example the following:

echo $form->create('User', array('action'=>'dashboard_profile'));

or this one:

echo $form->create('User', array('url'=>array('controller'=>'users', 'action'=>'dashboard_edit')));

generate the following (wrong) link: /users/dashboard_profile/1

While it does point to the right action (dashboard_profile) you get an error message explaining that this is a private action. The only way to use this private action is to use the prefix method.

The reason for this is that the form generate part in the cake code doesn’t do anything with the routing, thus ignoring the prefix we’ve set.

After some digging in the api i found a cake-way to generate the right url:

echo $form->create('User', array('url'=>$html->url(array('action'=>'dashboard_profile'))));

We use the html helper, that does parse the prefix part and generates a nice correct url, namely: /dashboard/user/profile

The html helper does check for any prefixes in the routing and generates the right url.
Combining the form->create and the html->url we get the right url.

Filed Under: CakePHP, Code, English - read on

Admin routes

I had some issues today with the admin routes in the new cake version.

The problem was that i was using an admin route in the core (/app/config/core.php)

/**
 * Uncomment the define below to use CakePHP admin routes.
 *
 * The value of the define determines the name of the route
 * and its associated controller actions:
 *
 * 'admin' 		-> admin_index() and /admin/controller/index
 * 'superuser' -> superuser_index() and /superuser/controller/index
 */
Configure::write('Routing.admin', 'dashboard');

And in my routes file (/app/config/routes.php) i was using this:

Router::connect('/dashboard/', array('controller' => 'sites', 'action' => 'index', 'admin'=>'dashboard'));

This didn’t work out as planned, it gave an error about not beeing able to find a controller action (index(); instead of dashboard_index();

Turns out that in the new version you need to use prefix instead of admin, so the line should be:

Router::connect('/dashboard/', array('controller' => 'sites', 'action' => 'index', 'prefix'=>'dashboard'));

Then in my app_controller (/app/app_controller.php) i had a function to switch to the admin layout if it was called in the url, but this changed also.

It used to be:

if (isset($this->params['dashboard'])) {
		$this->layout = 'dashboard';
	}

But i had to change it to:

if (isset($this->params['prefix']) && $this->params['prefix'] == 'dashboard') {
		$this->layout = 'dashboard';
	}

The reason for this is that it uses the prefix value from the routes file.
If you use the first example (the one with $this->params['dashboard']) the dashboard layout will not be set if there is no / after dashboard in the url (http://mysite.com/dashboard), because $this->params['dashboard'] will be empty.
Using the second example it will set the layout.

I also check if the prefix is dashboard, because you could be using more then one prefix.

Filed Under: CakePHP, Code, English - read on