CakePHP允许使用API​​按字段搜索?

时间:2016-08-29 15:55:13

标签: php cakephp cakephp-3.0

我正在尝试使用允许搜索的CakePHP创建API。例如:

http://localhost:8765/users/index/?username=admin

哪些用户名应该返回用户名等于' admin':

users: [
   {
      id: 3,
      username: "admin",
      image: "",
      firstName: "Jeremy",
      lastName: "Quick",
      userTypeId: 1,
      email: "jrquick@test.com",
      groupId: 2
   }
]

到目前为止,我已经能够通过AppController中的自定义get()来完成此操作,它会检查模型中字段的$ _GET和$ _POST数组。但随着我添加更多功能(范围搜索,集合搜索和子表过滤),该功能变得越来越复杂,并且越来越复杂。是否有更好的,更CakePHP友好的方式来实现这一目标?无论是通过纯蛋糕还是插件?

3 个答案:

答案 0 :(得分:1)

我想你想使用Cakephp搜索插件。它具有良好的文档,并使用类似于您当前使用的PRG方法。它将通过API正常运行。这是指向该插件的链接:github.com/FriendsOfCake/search

答案 1 :(得分:0)

如果您想创建API,首先应创建一个MiddleWare,它会过滤令牌,密钥等,以使您的API受到更多保护。 此外,您应该使用PluginsRESTful Routes,这将非常有帮助。

创建插件: bin/cake bake plugin Api

创建模型: bin/cake bake model Users

例如,您希望在Api插件中使用UsersController:

<?php  
namespace Api\Controller;

/* This controller will be extending like parent */
use Api\Controller\AppController;
use Api\Model\Table\UsersTable;
/**
* Class UsersController
* @package Api\Controller
* @property UsersTable $Users
* 
*/
class UsersController extends AppController{
   public function initialize(){
       parent::initialize();
       $this->loadModel('Api.Users');
   }

   public function getUser($field ='username', $username = false){
       return $this->_jsonResponse(
           [
             'users' => $this->Users->findBy{ucfirst($field)}($username)
           ];
       )
   }

   public function _jsonResponse($data, $code = 200){
       $this->response->type('json');
       $this->response->statusCode($code);
       $this->response->body(
           json_encode((array)$data)
       );
       return $this->response;
   }       

}

路线将在plugins/config/routes.php中进行描述。您需要在/api路径中为API创建路线图:

function (RouteBuilder $routes) {
    $routes->resources('Users', [
        'map' => [
            'get-user' => [
                'action' => 'getUser',
                'method' => 'GET' /* Can be also as array ['GET', 'PUT', 'DELETE'] */
            ]
        ]
    ]);

    $routes->fallbacks('DashedRoute');
}

如果您经常接听电话,则应使用Cache来拨打并保存一段时间。例如 - 10 minutes。可以在config/app.php中配置缓存。您应该创建单独的Cache前缀并以这种方式使用它:

<?php
use Cake\Cache\Cache;

$data = [];

Cache::write('some_key', $data, 'prefix') 
dump(Cache::read('some_key', 'prefix'));

这只是一个例子。如果您将遇到一些问题 - 请在评论中说明:)

另外,使用MigrationsSeeds代替转储sql文件

如果您想过滤来自中间件的数据 - 您应该有Event作为参数,它将包含请求数据($_POST)和请求查询($_GET)变量您将成为能够轻松处理。 来自控制器您需要使用$this->request->data获取POST数据数组或$this->request->query获取GET数据数组。

答案 2 :(得分:0)

我还没有找到一个似乎可以正常工作的答案,所以这是我当前的get命令。它允许按字段搜索,连接表,大于/小于,在数组中等。

如果有人提出改进建议,我会更新我的答案。

public function get() {
    $response = new Response();

    $model = $this->loadModel();

    $fields = $this->getFields();
    $joins = $this->getJoins();
    $order = $this->getOrder();
    $params = $this->getParams();
    $limit = $this->getLimit();
    $offset = $this->getOffset();

    $query = $model->find('all', ['fields' => $fields]);
    if (!is_null($joins)) {
        $query->contain($joins);
    }
    if (sizeof($params['equals']) > 0) {
        foreach ($params['equals'] as $equalsKey=>$equalsValue) {
            $query->andWhere([$equalsKey => $equalsValue]);
        }
    }
    if (sizeof($params['or']) > 0) {
        foreach ($params['or'] as $orKey=>$orValue) {
            $query->orWhere([$orKey => $orValue]);
        }
    }
    if (!is_null($order)) {
        $query->order([$order]);
    }
    if (!is_null($limit)) {
        $query->limit($limit);
        if (!is_null($offset)) {
            $query->offset($offset);
        }
    }
    $response->addMessage($model->table(), $query->toArray());

    $response->respond($this);
}

private function getFields() {
    $fields = [];
    if (array_key_exists('fields', $_GET)) {
        $fields = explode(',', $_GET['fields']);
    }

    return $fields;
}

private function getLimit() {
    $limit = null;
    if (array_key_exists('limit', $_GET)) {
        $limit = $_GET['limit'];
    }

    return $limit;
}

private function getJoins() {
    $joins = null;
    if (array_key_exists('joins', $_GET)) {
        $joins = explode(',', $_GET['joins']);
    }

    return $joins;
}

private function getOffset() {
    $offset = null;
    if (array_key_exists('offset', $_GET)) {
        $offset = $_GET['limit'];
    }

    return $offset;
}

private function getOrder() {
    $results = [];

    if (array_key_exists('order', $_GET)) {
        $orders = explode(',', $_GET['order']);

        foreach ($orders as $order) {
            $sign = substr($order, 0, 1);
            $direction = 'ASC';
            if (in_array($sign, ['+', '-'])) {
                if ($sign === '-') {
                    $direction = 'DESC';
                }

                $order = substr($order, 1);
            }

            $result = $order;
            if (strpos($result, '.') === false) {
                $result = $this->loadModel()->alias() . '.' . $order;
            }
            $result = $result . ' ' . $direction;

            $results[] = $result;
        }
    }

    return (sizeof($results) == 0) ? null : implode(',', $results);
}

private function getParams() {
    $params = [
        'equals' => [],
        'or'     => []
    ];

    $parentModel = $this->loadModel();

    $array = array_merge($_GET, $_POST);
    foreach ($array as $field=>$value) {
        $comparisonType = 'equals';
        $operator = substr($field, strlen($field) - 1);
        if (in_array($operator, ['!', '>', '<'])) {
            $field = substr($field, 0, strlen($field) - 1);
            $operator .= '=';
        } else if (in_array($operator, ['|'])) {
            $field = substr($field, 0, strlen($field) - 1);
            $comparisonType = 'or';
            $operator = '=';
        } else if (in_array($operator, ['%'])) {
            $field = substr($field, 0, strlen($field) - 1);
            $operator = 'LIKE';
            $value = '%'.$value.'%';
        } else {
            $operator = '=';
        }

        if ($value == 'null') {
            $operator = (strpos($operator, '!') === false) ? 'IS' : 'IS NOT';
            $value = null;
        }

        $field = str_replace('_', '.', $field);
        if (strpos($field, '.') === false) {
            $alias = $parentModel->alias();
        } else {
            $fieldExplosion = explode('.', $field);
            $alias = $fieldExplosion[0];
            $field = $fieldExplosion[1];
        }

        $model = null;
        if ($parentModel->alias() !== $alias) {
            $association = $parentModel->associations()->get($alias);
            if (!is_null($association)) {
                $model = $this->loadModel($association->className());
            }
        } else {
            $model = $parentModel;
        }

        if (!is_null($model)) {
            if ($model->hasField(rtrim($field, 's')) && !$model->hasField($field)) {
                $field = rtrim($field, 's');
                $value = '(' . $value . ')';
                $operator = ' IN';
            }

            if ($model->hasField($field)) {
                $params[$comparisonType][$alias.'.'.$field . ' ' . $operator] = $value;
            }
        }
    }

    return $params;
}