Does CakePHP allow you to search by field using the API?

I am trying to create an API using CakePHP which allows searching. For instance:

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

Which should return users with usernames equal to "admin":

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

So far, I have been able to accomplish this with a custom get () in the AppController, which checks the $ _GET and $ _POST array for model fields. But the function is becoming more complex and bordering on hacking as I add more functionality (range search, collection search and filtering of child tables). Is there a better, more appropriate CakePHP way to do this? Does it through a clean trick or plugin?

+5
source share
3 answers

I did not find an answer that seems to work exactly the way I want, so here is my current get command. This allows you to search by fields, join tables, more / less, in an array, etc.

If anyone has recommendations for improvement, I will update my answer.

 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; } 
0
source

I think you want to use the Search Cakephp plugin. It has good documentation and uses a PRG method similar to that currently used. It works great through the API. Here is a link to this plugin: github.com/FriendsOfCake/search

+1
source

If you want to create an API, you first need to create MiddleWare , which will filter tokens, keys, etc., to make your API more secure. In addition, you should use Plugins and RESTful Routes , which will be very useful.

To create a plugin: bin/cake bake plugin Api

Create Model: bin/cake bake model Users

For example, you want to have a UserController in the Api plugin:

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

The route will be described in plugins/config/routes.php . You need to create a route map for the API in the /api path:

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

If you have frequent calls, you should use Cache , which calls and stores them for some time. For example, 10 minutes . The cache can be configured in config/app.php . You must create a separate cache prefix and use it as follows:

 <?php use Cake\Cache\Cache; $data = []; Cache::write('some_key', $data, 'prefix') dump(Cache::read('some_key', 'prefix')); 

These are just examples. If you have some problems - just tell me in the comments :)

Also, use migrations and seeds instead of dumping sql files

If you want to filter data from Middleware, you should have Event as an argument, which will contain the request data ( $_POST ) and request requests ( $_GET ), which you can easily handle. From the controllers, you need to use $this->request->data to get the POST data array or $this->request->query to get the GET data array.

0
source

All Articles