How to connect a post rest request to the add controller action using prefixes in cakephp

一曲冷凌霜 提交于 2020-01-05 08:23:10

问题


I code a client/server application.

  • Server side is powered by CakePHP 2.4.7.
  • Client side run with angularjs and cordova on mobile devices

I use several cakephp route prefixes whose 'admin' and 'mobile'. (And I use $resource and $httpInterceptor angularjs factories to setup my REST requests.)

I want to call /website/mobile/posts/add.json with json data posting.

So I call /website/mobile/posts.json with a POST ajax query:

The problem is here: the called controller action is 'index', not 'add';

On top of my PostsController, I added this:

echo $this->request->params['action'] . "\n";
echo ($this->request->isPost())? "post" . "\n" : "not post";
die;

and the response is always:

mobile_index
post

So the ajax request seems correct but cakephp don't map it to the add action, but index one. However my configuration seems good too; here is a fragment of my routes.php

Router::mapResources(array('users','posts'));
Router::parseExtensions('json');

Any idea ?


回答1:


Prefix routing doesn't work with REST routing out of the box

REST routing works by automatically creating routes for the controllers passed to Router::mapResources(). Prefix routing pretty much does the same, it creates default routes including the prefixes defined in Routing.prefixes.

However both functionalities don't know about each other, they both create separte routes, so Router::mapResources() will connect to URLs without prefixes (the prefix option for this method is not using actual prefix routing, it will just add the value of that option to the beginning of the URL to connect to!), and therefore your request to /mobile/... doesn't actually use REST routing but only prefix routing.

Defining prefixed REST routes manually

There is no simple fix for this problem like using an option or something, instead you'll have to define the REST routes manually so that the prefix option is included, simple enough though.

See Modifying the default REST routes and Custom REST Routing.

A sample Route could look like this:

Router::connect(
    '/mobile/users',
    array(
        'prefix' => 'mobile',
        'mobile' => true,
        'controller' => 'users',
        'action' => 'add',
        '[method]' => 'POST'
    )
);

This would connect POST requests to /mobile/users to UsersController::mobile_add(). Similary you'll have to do this for all other methods like GET and PUT, with and without passing an id, etc.

Note that when connecting manually you can ditch the Routing.prefixes option and of course the call to Router::mapResources().

Automated mapping

Defining all those routes by hand is kinda exhausting, you're better of automating it with respect to the Router::resourceMap() configuration.

Here's an example on how to do that, it's somewhat similar to Router::mapResources(), but it accepts a prefix option that actually makes use of prefix routing:

function mapResources(array $controllers) {
    $resourceMap = Router::resourceMap();

    foreach($controllers as $controller => $options) {
        if(!is_array($options)) {
            $controller = $options;
            $options = array();
        }
        $options += array(
            'prefix' => null,
            'plugin' => null,
            'id' => Router::ID . '|' . Router::UUID
        );

        foreach($resourceMap as $params) {
            $url = '';
            if($options['prefix']) {
                $url .= '/' . $options['prefix'];
            }
            if($options['plugin']) {
                $url .= '/' . $options['plugin'];
            }
            $url .= '/' . $controller;
            if($params['id']) {
                $url .= '/:id';
            }

            Router::connect(
                $url,
                array(
                    'prefix' => $options['prefix'],
                    $options['prefix'] => !!$options['prefix'],
                    'plugin' => $options['plugin'],
                    'controller' => $controller,
                    'action' => $params['action'],
                    '[method]' => $params['method']
                ),
                array(
                    'id' => $options['id'],
                    'pass' => array('id')
                )
            );
        }
    }
}

You would call it like this:

mapResources(array(
    'books' => array(
        'prefix' => 'mobile'
    )
));

and it would map all the REST routes for your books controller using the mobile prefix.



来源:https://stackoverflow.com/questions/24382283/how-to-connect-a-post-rest-request-to-the-add-controller-action-using-prefixes-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!