2016-08-29 27 views
5

Tôi đang cố tạo một API bằng CakePHP cho phép tìm kiếm. Ví dụ:CakePHP cho phép tìm kiếm theo trường bằng API?

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

nào phải trả lại cho người dùng với tên người dùng bằng để 'admin':

users: [ 
    { 
     id: 3, 
     username: "admin", 
     image: "", 
     firstName: "Jeremy", 
     lastName: "Quick", 
     userTypeId: 1, 
     email: "[email protected]", 
     groupId: 2 
    } 
] 

Cho đến nay, tôi đã có thể thực hiện điều này với một phong tục get() trong AppController mà kiểm tra mảng $ _GET và $ _POST cho các trường trên mô hình. Nhưng chức năng ngày càng trở nên phức tạp và verging trên hackiness như tôi thêm nhiều chức năng hơn (tìm kiếm phạm vi, tìm kiếm bộ sưu tập, và lọc bảng con). Có cách nào tốt hơn, CakePHP thân thiện hơn để hoàn thành việc này không? Cho dù thông qua cakephp tinh khiết hoặc một plugin?

+0

Lưu ý phụ, không bao giờ truy cập trực tiếp superglobals khi sử dụng CakePHP, điều này sẽ mang lại cho bạn sự cố, đặc biệt khi làm việc với kiểm tra bộ điều khiển! Sử dụng trình bao bọc được cung cấp trên [** đối tượng yêu cầu **] (http://book.cakephp.org/3.0/en/controllers/request-response.html#query-string-parameters) để thay thế. – ndm

+1

Chỉ cần sử dụng plugin Bạn bè của Tìm kiếm bánh. Nó cũng được viết, nhỏ, dễ sử dụng và bạn có thể thực hiện https://en.wikipedia.org/wiki/Post/Redirect/Get với nó. Nó làm cho nó thực sự dễ dàng. – burzum

Trả lời

0

Tôi chưa tìm thấy câu trả lời có vẻ như hoạt động chính xác theo cách tôi muốn, vì vậy đây là lệnh get hiện tại của tôi. Nó cho phép tìm kiếm theo các trường, nối các bảng, lớn hơn/ít hơn, trong mảng, và tương tự.

Nếu có đề xuất cải thiện, tôi sẽ cập nhật câu trả lời của mình.

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; 
} 
1

Tôi nghĩ bạn muốn sử dụng plugin Tìm kiếm Cakephp. Nó có tài liệu tốt và sử dụng một phương pháp PRG tương tự như những gì bạn đang sử dụng. Nó sẽ hoạt động tốt thông qua một API. Đây là liên kết tới plugin đó: github.com/FriendsOfCake/search

0

Nếu bạn muốn tạo API, ban đầu bạn nên tạo MiddleWare để lọc mã thông báo, khóa, v.v. Ngoài ra, bạn nên sử dụng PluginsRESTful Routes, điều này sẽ rất hữu ích.

Để tạo plugin: bin/cake bake plugin Api

Tạo mẫu: bin/cake bake model Users

Ví dụ, Bạn muốn có UsersController trong plugin Api:

<?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; 
    }  

} 

Route sẽ được descripbed trong plugins/config/routes.php. Bạn cần phải tạo Route Map API trong /api đường dẫn:

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

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

Nếu bạn có các cuộc gọi thường xuyên, bạn nên sử dụng Cache mà các cuộc gọi và lưu chúng trong một khoảng thời gian. Ví dụ: 10 minutes. Bộ nhớ cache có thể được cấu hình trong config/app.php. Bạn nên tạo tiền tố Cache riêng biệt và sử dụng nó theo cách này:

<?php 
use Cake\Cache\Cache; 

$data = []; 

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

Đó chỉ là ví dụ. Nếu Bạn sẽ phải đối mặt với một số vấn đề - chỉ nói trong ý kiến ​​:)

Ngoài ra, sử dụng MigrationsSeeds thay vì bán phá giá các file sql

Nếu bạn muốn lọc dữ liệu từ Middleware - Bạn nên có Event như là đối số, sẽ chứa yêu cầu dữ liệu ($_POST) và yêu cầu truy vấn ($_GET) biến mà bạn sẽ có thể dễ dàng xử lý. Từ bộ điều khiển Bạn cần sử dụng $this->request->data để nhận POST mảng dữ liệu hoặc $this->request->query để nhận mảng dữ liệu GET.

+0

Ngoài ra, phương thức '_jsonResponse()' nên được đặt trong 'src/Controller/AppController.php' (Bộ điều khiển chính) để có quyền truy cập từ bất kỳ đâu và có một trình điều khiển truy cập' được bảo vệ'. –

+0

Tuyến đường cho cuộc gọi này sẽ là: 'http://example.com/ {plugin_path}/{controller}/{method}' - 'http://example.com/api/users/get-user/firstName/Jeremy' –

+0

Lưu ý rằng nó sẽ trả về 'ứng dụng/json' của bạn dưới dạng' Loại nội dung'. Với điều này, bạn không cần phải đối phó với 'JSON.parse (obj)', bởi vì nó sẽ được tự động chuyển thành 'đối tượng' theo kiểu nội dung –

Các vấn đề liên quan