【问题标题】:CakePHP allow searching by field using API?CakePHP 允许使用 API 按字段搜索?
【发布时间】:2016-08-29 15:55:13
【问题描述】:

我正在尝试使用 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 数组。但是随着我添加更多功能(范围搜索、集合搜索和子表过滤),该功能变得越来越复杂并且接近于hackiness。有没有更好的、对 CakePHP 更友好的方式来实现这一点?是通过纯 cakephp 还是插件?

【问题讨论】:

  • 旁注,在使用 CakePHP 时不要直接访问超全局变量,这只会给你带来麻烦,尤其是在使用控制器测试时!请改用the request object 上提供的包装器。
  • 只需使用蛋糕搜索之友插件。它写得很好,体积小,易于使用,你可以用它实现en.wikipedia.org/wiki/Post/Redirect/Get。这真的很容易。

标签: php cakephp cakephp-3.0


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    如果您想创建 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 创建 Route Map:

    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'));
    

    这只是例子。如果您将面临一些问题 - 只需告诉 cmets :)

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

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

    【讨论】:

    • 另外,_jsonResponse() 方法应该位于 src/Controller/AppController.php(主控制器)中,以便可以从任何地方访问并具有 protected 访问修改器。
    • 此呼叫的路由将是:http://example.com/{plugin_path}/{controller}/{method} - http://example.com/api/users/get-user/firstName/Jeremy
    • 请注意,它将以Content-Type 的形式返回您application/json。有了这个,你就不需要处理JSON.parse(obj),因为它会根据内容类型自动转换成object
    【解决方案3】:

    我还没有找到似乎完全符合我要求的答案,所以这是我当前的 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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-03
      相关资源
      最近更新 更多