webentwicklung-frage-antwort-db.com.de

Yii2 REST Abfrage

Hy. Ich habe einen ProductController, der die yii\rest\ActiveController erweitert. Die Frage ist, wie ich Abfragen über HTTP-GET-Anfrage machen kann.

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

Und das zurückgegebene Objekt enthält alle Produkte mit dem Namen iphone.

18
Kedves Hunor

Ok, ich habe rausgefunden, lege dies einfach in deinen Controller und ändere den URL-Router in der Konfiguration.

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

Und die URL-Regel (Bearbeiten)

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

UPDATE: 29. April 2016

Dies ist ein Ansatz, der einfacher ist als der, den ich im vorherigen Update eingeführt habe. Es geht immer darum, die Search -Klasse einzubeziehen, die von gii generiert wurde. Ich verwende es gerne, um die gesamte suchbezogene Logik an einem einzigen Ort zu definieren und zu verwalten, beispielsweise mithilfe von benutzerdefinierten Szenarien, Validierungen oder verwandten Modellen für den Filterprozess (wie in diesem Beispiel ). Also gehe ich zurück zu meiner ersten Antwort:

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

Stellen Sie dann sicher, dass Ihre Suchklasse load($params,'') anstelle von load($params) verwendet, oder fügen Sie dies alternativ zum Modell hinzu Klasse:

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

Das sollte ausreichen, damit Ihre Anfragen so aussehen:

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


UPDATE: 23. September 2015

Dies ist der gleiche Ansatz, jedoch durch Implementierung einer vollständigen und saubereren Lösung:

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

Jetzt sieht Ihre GET-Anfrage so aus:

/ products? name = iphone

Oder auch gerne:

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

  • Hinweis:

    Wenn Sie anstelle von /products?name=iphone Nach einer bestimmten Aktion suchen, um Such- oder Filteranforderungen zu verarbeiten, wie z.

    / products/search? name = iphone

    Im obigen Code müssen Sie dann die Aktionsfunktion mit ihrem gesamten Inhalt entfernen :

    public function actions() { ... }

    Umbenennen : indexDataProvider() in actionSearch()

    & schließlich fügen Sie 'extraPatterns' => ['GET search' => 'search'] zu Ihren yii\web\UrlManager :: rules hinzu, wie in @ beschrieben. KedvesHunors Antwort.


Ursprüngliche Antwort: 31. Mai 2015

Es gibt eine kurze Möglichkeit, dies zu tun. Wenn Sie beim Generieren von CRUD für Ihr Modell Gii eine Modellklasse suchen definiert haben, können Sie diese verwenden Um die Ergebnisse zu filtern, müssen Sie lediglich die prepareDataProvider -Funktion von indexAction überschreiben, um die Rückgabe der von der ActiveDataProvider -Funktion von _ zurückgegebenen search -Instanz zu erzwingen Ihr Modell Suchklasse anstatt eine benutzerdefinierte neue zu erstellen.

Um fortzufahren, ob Ihr Modell Product.php ist und Sie eine ProductSearch.php generiert haben -) als Klasse suchen dazu, dann müssen Sie in Ihrem Controller nur Folgendes hinzufügen:

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

Zum Filtern der Ergebnisse könnte Ihre URL dann so aussehen:

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

oder auch so:

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

Ich würde nicht empfehlen, Superglobals $ _GET direkt zu verwenden. Stattdessen können Sie Yii :: $ app-> request-> get () verwenden.

Das folgende Beispiel zeigt, wie Sie eine generische Suchaktion erstellen und in der Steuerung verwenden können.

Am Controller Ende

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

Benutzerdefinierte Suchaktion

<?php

namespace app\[YOUR NAMESPACE];

use Yii;
use yii\data\ActiveDataProvider;
use yii\rest\Action;


class SearchAction extends Action {

    /**
     * @var callable a PHP callable that will be called to prepare a data provider that
     * should return a collection of the models. If not set, [[prepareDataProvider()]] will be used instead.
     * The signature of the callable should be:
     *
     * ```php
     * function ($action) {
     *     // $action is the action object currently running
     * }
     * ```
     *
     * The callable should return an instance of [[ActiveDataProvider]].
     */
    public $prepareDataProvider;
    public $params;

    /**
     * @return ActiveDataProvider
     */
    public function run() {
        if ($this->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;
    }

}
8
Rx Seven

In Config/web.php -> 'extraPatterns' hinzufügen => ['GET search' => 'search']

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

** In Rest Api Controller: - Moduels/v1/controller/** 

basicinfo: - Ist Ihr Controller Name, Name und Alter ist Ihr Fields Name. Sie können alle Parameter hinzufügen, die in Ihrer Tabelle vorhanden sind.

URL suchen LIKE: - basicinfo/search? Name = yogi & age = 12-23

Include use 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');
    }
}
2
Gaurav verma

Wenn Sie auf Ihre API zugreifen möchten: api/product/index?name=fashion ein kürzerer Weg zum Filtern wäre:
- Deaktivieren Sie die Aktion, in meinem Fall index action.

public function actions()
{
    $actions = parent::actions(); 
    unset($actions['index']);
    return $actions;
}
  • Führen Sie eine benutzerdefinierte Abfrage wie unten gezeigt durch.

    öffentliche Funktion actionIndex () {

    $query = Product::find();
    $dataProvider =  new ActiveDataProvider([
        'query' => $query,
        'pagination' => [
                'pageSize' => 1,
            ],
    ]);
    
    if (isset($_GET['name']) && !empty($_GET['name'])) {
        $searchWord = strtolower(trim($_GET['name']));
        $query->andFilterWhere(['like', 'name', $searchWord]);
    }
    
    return $dataProvider;
    

    }

0
ovicko

Seit yii 2.0.13 hat yii\rest\IndexAction die neue Eigenschaft - dataFilter, die den Filtervorgang vereinfacht. Standardmäßig verwendet ActiveController yii\rest\IndexAction für die Aktion index:

    class ActiveController extends Controller {
        public function actions()
        {
            return [
                'index' => [
                    'class' => 'yii\rest\IndexAction',
                    'modelClass' => $this->modelClass,
                    'checkAccess' => [$this, 'checkAccess'],
                ]
        }
}

Führen Sie im Controller ProductController Folgendes aus:

class ProductController extends ActiveController
{
    public function actions()
    {
        $actions = parent::actions();

        $actions['index']['dataFilter'] = [
            'class' => 'yii\data\ActiveDataFilter',
            'searchModel' => 'app\models\ProductSearch'
        ];

        return $actions;
    }
}

Angenommen, app\models\ProductSearch ist das Produktfiltermodell.

0
mirushaki