I'm trying to implement REST and parseExtension like functionality in my app, running on CakePHP 2.

Instead of having URLs like http://myapp.dev/controller/action.json I would like to use http://myapp.dev/json/controller/action.

The reason for this is that sometimes extensions look a little stupid when put onto something like http://myapp.dev/controller/index/show:10/page:2.json.

While this could be implemented in a custom route, I already have lots of custom routes, and do not want to have to create duplicates of each with a :type field in there for maintenance reasons.

What would be ideal is setting it up such that any url with /json /xml /html etc. in first place would be treated as if json, xml, html etc. were the extension.

While Prefix Routing looks ideal for this, it requires new methods (e.g. json_index, html_index etc. and I would have to specify each format as a separate prefix).

Is there any good way of doing this? I just want parseExtensions to instead be like a parsePrefixes method instead.

有帮助吗?

解决方案

You should try the following :

Router::connect('/:ext/', array(':ext'), array('pass' => 'ext'));
Router::connect('/:ext/:controller/*', array(':ext'), array('pass' => 'ext'));
Router::connect('/:ext/:controller/:action/*', array(':ext'), array('pass' => 'ext'));

Then, the router will pass the :ext argument, in the "ext" value of the route parameters. Add it for all your rules !

If you want to use traditionnel routes to work, you need to use a custom CakeRoute. Create a file "/libs/routes/RestRoute.php" in your app folder, add the following into it :

class RestRoutes extends CakeRoute {
    function parse($url) {
        $params = parent::parse($url);

        if (empty($params)) {
            return false;
        }

        if(!in_array($params['ext'], Router::extensions())) {
            return false;
        }

        return $params;
    }
}

And in your /core/routes.php :

App::import('Lib', 'routes/RestRoute');
Router::connect('/:ext/', array(':ext'), array('pass' => 'ext', 'routeClass' => 'RestRoute'));
Router::connect('/:ext/:controller/*', array(':ext'), array('pass' => 'ext', 'routeClass' => 'RestRoute'));
Router::connect('/:ext/:controller/:action/*', array(':ext'), array('pass' => 'ext', 'routeClass' => 'RestRoute'));

So, when your custom route won't be able to pass an url, it would try the default url, without the ext parameters. Otherwise, the order of the parameters are not quiet allright.

Maybe not the best or cleaner solution, but it's a good start.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top