Home > CakePHP Development > Reverse prefix routing in CakePHP

Reverse prefix routing in CakePHP

After having worked on a particularly annoying problem involving the CakePHP custom prefix routing, I feel like I might have found a slight bug in the reverse routing (specifically, in a URL generated when calling Router::url()).

Let me set out a test scenario, so that I can fully explain what it is that I am trying to do. In this test scenario, we’ve got a bustling social networking site. But now, we want to WAP-enable this site – basically, we’re going to optimise it to be viewed on mobile phones. However, in order to keep the WAP section separate, we’re going to use a custom prefix, wap.

So, as an example URL, if a user wanted to log in to this mobile site, they would visit /wap/users/login, as opposed to /users/login on the main site. Additionally, when a user visits /wap, this is the exact same as visiting /wap/users/login.

So, we can now set up our first route that would fulfill this functionality:

Router::connect('/wap/', array(
'controller' => 'users',
'action' => 'login',
'prefix' => 'wap',
'wap' => true));

This works correctly. However, what happens if I want to link to that route from a hyperlink contained somewhere in the page? I supply an array for the URL portion of the HtmlHelper::link() method. So, you would think that using the following snippet of code, you would be provided with the correct URL:

echo $html->link('Foo', array(
'controller' => 'users',
'action' => 'login',
'prefix' => 'wap',
'wap' => true
));

However, this is, unfortunately, not the case. In my experience (using Cake version 1.2.1.8004), the actual output obtained is something more along the lines of /users/login/wap:1 – so it seems as if the custom prefix is being ignored. However, I do believe I might have been able to pinpoint the bit of code in Cake that prevents the prepending of this prefix to the URL, as well as a possible solution that I’ve proposed.

The code that handles this part of the routing can be found around line 880 in the Router core library definition:

$urlOut = Set::filter(array($url['controller'], $url['action']));

Now, from what I can make out, this is creating the “front” part of the URL – the first two sections of the URL. Notice that only the controller and the action are taken into account. This means that the custom prefix can never actually come into play, and is always ignored. The following code snippet is my proposed solution to fix this:

if (empty($url['action'])) {
if (empty($url['controller']) || $params['controller'] === $url['controller']) {
$url['action'] = $params['action'];
} else {
$url['action'] = 'index';
}
}
// start additions
$prefix = null;
if(isset($url['prefix']) && isset($url[$url['prefix']]) && $url[$url['prefix']] === true) {
$prefix = $url['prefix'];
unset($url[$url['prefix']]);
} else {
$prefix = null;
}
// ... move down to about line 880
$urlOut = Set::filter(array($prefix, $url['controller'], $url['action']));
// end additions

So, these are my findings and proposals. I’ve only recently made this change in my core libraries, but have yet to come across any issues brought on by this change. Do you have any suggestions or comments on this? If so, drop them in the comments.

Edit: I’ve posted this same question in the CakePHP Google Groups. You can view it at http://groups.google.com/group/cake-php/browse_thread/thread/c9a40ee702bb7b89.

  1. May 22nd, 2009 at 02:31 | #1

    @Geoff Garbers

    Saw your email. ;) No problem, I have been using using reverse routing quite a lot and it is really useful. I am quite sure it works the same for pagination.

    Cheers.

    P.S. Think you need the subscribe to comments WP plugin. :p

  2. May 15th, 2009 at 14:15 | #2

    Shot, Derick. That seems to work just fine. I haven’t tried it when using pagination, just yet. Plan on trying to get around to that sometime soon.

  3. May 9th, 2009 at 15:30 | #3

    Leave out the prefix key when passing the url to $html->link(). That should work.

  1. No trackbacks yet.
Security Code: