Consulta REST Yii2

Hy. Tengo un ProductController que extiende el yii \ rest \ ActiveController. La pregunta es cómo puedo hacer consultas a través de la solicitud HTTP GET.

Me gusta: http: //api.test.loc/v1/products/search? Name = iphone

Y el objeto de devolución contendrá todos los productos con el nombre iphone.

ACTUALIZACIÓN: 29 de abril de 2016

Este es un enfoque más simple que el que presenté en la actualización anterior. Siempre se trata de involucrar a la clase de búsqueda generada por gii . Me gusta usarlo para definir y mantener toda la lógica relacionada con la búsqueda en un solo lugar, como utilizar escenarios personalizados, manejar validaciones o involucrar modelos relacionados en el proceso de filtrado (como en este ejemplo ). Así que estoy volviendo a mi primera respuesta:

public function actions() { $actions = parent::actions(); $actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider']; return $actions; } public function prepareDataProvider() { $searchModel = new \app\models\ProductSearch(); return $searchModel->search(\Yii::$app->request->queryParams); } 

Luego, asegúrese de que su clase de búsqueda esté utilizando load($params,'') lugar de load($params) o, alternativamente, agregue esto a la clase de modelo :

 class Product extends \yii\db\ActiveRecord { public function formName() { return ''; } 

Eso debería ser suficiente para que sus solicitudes se vean así:

/ products? name = iphone & status = disponible & sort = name, -price


ACTUALIZACIÓN: 23 de septiembre de 2015

Este es el mismo enfoque pero al implementar una solución completa y más limpia:

 namespace app\api\modules\v1\controllers; use yii\rest\ActiveController; use yii\helpers\ArrayHelper; use yii\web\BadRequestHttpException; class ProductController extends ActiveController { public $modelClass = 'app\models\Product'; // Some reserved attributes like maybe 'q' for searching all fields at once // or 'sort' which is already supported by Yii RESTful API public $reservedParams = ['sort','q']; public function actions() { $actions = parent::actions(); // 'prepareDataProvider' is the only function that need to be overridden here $actions['index']['prepareDataProvider'] = [$this, 'indexDataProvider']; return $actions; } public function indexDataProvider() { $params = \Yii::$app->request->queryParams; $model = new $this->modelClass; // I'm using yii\base\Model::getAttributes() here // In a real app I'd rather properly assign // $model->scenario then use $model->safeAttributes() instead $modelAttr = $model->attributes; // this will hold filtering attrs pairs ( 'name' => 'value' ) $search = []; if (!empty($params)) { foreach ($params as $key => $value) { // In case if you don't want to allow wired requests // holding 'objects', 'arrays' or 'resources' if(!is_scalar($key) or !is_scalar($value)) { throw new BadRequestHttpException('Bad Request'); } // if the attr name is not a reserved Keyword like 'q' or 'sort' and // is matching one of models attributes then we need it to filter results if (!in_array(strtolower($key), $this->reservedParams) && ArrayHelper::keyExists($key, $modelAttr, false)) { $search[$key] = $value; } } } // you may implement and return your 'ActiveDataProvider' instance here. // in my case I prefer using the built in Search Class generated by Gii which is already // performing validation and using 'like' whenever the attr is expecting a 'string' value. $searchByAttr['ProductSearch'] = $search; $searchModel = new \app\models\ProductSearch(); return $searchModel->search($searchByAttr); } } 

Ahora su solicitud GET se verá así:

/ productos? nombre = iphone

O incluso como:

/ products? name = iphone & status = disponible & sort = name, -price

  • Nota:

    Si en lugar de /products?name=iphone está buscando una acción específica para manejar búsquedas o solicitudes de filtrado como:

    / products / search? name = iphone

    Luego, en el código anterior, deberá eliminar la función de acciones con todo su contenido:

     public function actions() { ... } 

    renombrar : indexDataProvider() a actionSearch()

    y finalmente agregue 'extraPatterns' => ['GET search' => 'search'] a sus reglas yii \ web \ UrlManager :: como se describe en la respuesta de @KedvesHunor.


Respuesta original: 31 de mayo de 2015

Hay una forma breve de hacerlo, si al usar Gii para generar CRUD para su modelo, definió una Clase de modelo de búsqueda , luego puede usarla para filtrar los resultados, todo lo que tiene que hacer es anular la función indexAction de indexAction para forzarlo a devolver la instancia ActiveDataProvider devuelta por la función de search de su clase de búsqueda modelo en lugar de crear una nueva personalizada.

Para reanudar si su modelo es Product.php y generó un ProductSearch.php como una clase de búsqueda para él, entonces en su Controlador solo necesita agregar esto:

 public function actions() { $actions = parent::actions(); $actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider']; return $actions; } public function prepareDataProvider() { $searchModel = new \app\models\ProductSearch(); return $searchModel->search(\Yii::$app->request->queryParams); } 

Luego, para filtrar los resultados, su url puede verse así:

 api.test.loc/v1/products?ProductSearch[name]=iphone 

o incluso así:

 api.test.loc/v1/products?ProductSearch[available]=1&ProductSearch[name]=iphone 

Ok, me di cuenta, solo pon esto en tu Controlador y modifica el enrutador de URL en config.

 public function actionSearch() { if (!empty($_GET)) { $model = new $this->modelClass; foreach ($_GET as $key => $value) { if (!$model->hasAttribute($key)) { throw new \yii\web\HttpException(404, 'Invalid attribute:' . $key); } } try { $provider = new ActiveDataProvider([ 'query' => $model->find()->where($_GET), 'pagination' => false ]); } catch (Exception $ex) { throw new \yii\web\HttpException(500, 'Internal server error'); } if ($provider->getCount() <= 0) { throw new \yii\web\HttpException(404, 'No entries found with this query string'); } else { return $provider; } } else { throw new \yii\web\HttpException(400, 'There are no query string'); } } 

Y la regla de URL (editar)

 'urlManager' => [ 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'rules' => [ ['class' => 'yii\rest\UrlRule', 'controller' => ['v1/product'], 'extraPatterns' => ['GET search' => 'search']], ], ], 

No recomendaría usar Superglobals $ _GET directamente. En su lugar, puede usar Yii :: $ app-> request-> get ().

A continuación se muestra el ejemplo de cómo puede crear una acción de búsqueda genérica y usarla en el controlador.

En el controlador End

 public function actions() { $actions = [ 'search' => [ 'class' => 'app\[YOUR NAMESPACE]\SearchAction', 'modelClass' => $this->modelClass, 'checkAccess' => [$this, 'checkAccess'], 'params' => \Yii::$app->request->get() ], ]; return array_merge(parent::actions(), $actions); } public function verbs() { $verbs = [ 'search' => ['GET'] ]; return array_merge(parent::verbs(), $verbs); } 

Acción de búsqueda personalizada

 checkAccess) { call_user_func($this->checkAccess, $this->id); } return $this->prepareDataProvider(); } /** * Prepares the data provider that should return the requested collection of the models. * @return ActiveDataProvider */ protected function prepareDataProvider() { if ($this->prepareDataProvider !== null) { return call_user_func($this->prepareDataProvider, $this); } /** * @var \yii\db\BaseActiveRecord $modelClass */ $modelClass = $this->modelClass; $model = new $this->modelClass([ ]); $safeAttributes = $model->safeAttributes(); $params = array(); foreach($this->params as $key => $value){ if(in_array($key, $safeAttributes)){ $params[$key] = $value; } } $query = $modelClass::find(); $dataProvider = new ActiveDataProvider([ 'query' => $query, ]); if (empty($params)) { return $dataProvider; } foreach ($params as $param => $value) { $query->andFilterWhere([ $param => $value, ]); } return $dataProvider; } } 

En Config / web.php -> Añadir ‘extraPatterns’ => [‘GET search’ => ‘buscar’]

 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => [['class' => 'yii\rest\UrlRule', 'controller' => 'v1/basicinfo', 'pluralize'=>false,'extraPatterns' => ['GET search' => 'search']]]] 

** Controlador Rest Api: – Moduels / v1 / controllers / **

basicinfo: – El nombre, el nombre y la edad de su controlador son los nombres de sus campos. Puede agregar todos los parámetros que existen en su tabla.

URL de búsqueda LIKE: – basicinfo / search? Name = yogi & age = 12-23

Incluir uso yii \ data \ ActiveDataProvider;

  public function actionSearch() { if (!empty($_GET)) { $model = new $this->modelClass; foreach ($_GET as $key => $value) { if (!$model->hasAttribute($key)) { throw new \yii\web\HttpException(404, 'Invalid attribute:' . $key); } } try { $query = $model->find(); foreach ($_GET as $key => $value) { if ($key != 'age') { $query->andWhere(['like', $key, $value]); } if ($key == 'age') { $agevalue = explode('-',$value); $query->andWhere(['between', $key,$agevalue[0],$agevalue[1]]); } } $provider = new ActiveDataProvider([ 'query' => $query, 'sort' => [ 'defaultOrder' => [ 'updated_by'=> SORT_DESC ] ], 'pagination' => [ 'defaultPageSize' => 20, ], ]); } catch (Exception $ex) { throw new \yii\web\HttpException(500, 'Internal server error'); } if ($provider->getCount() <= 0) { throw new \yii\web\HttpException(404, 'No entries found with this query string'); } else { return $provider; } } else { throw new \yii\web\HttpException(400, 'There are no query string'); } }