鬼一浪人 2023-12-08 12:43:22 766次浏览 0条评论 0 0 0

缘由:在做rest接口时,在actionIndex方法中使用dataFilter,其默认使用的是ActiveDataFilter::class, 现有的ActiveDataFilter::class类属性$filterAttributeName默认值为filter,在实际的过滤参数传递时,格式为:
1、filter[username][like]=yii表示username like yii;
2、filter[username]=yii表示username = yii;
问题是,get传递的参数实在是太长,如何可以通过GET参数 username=yii 来做到同样的效果呢?

经过实际的代码,实现如下:
1、定义一个类,处于app\models命名空间下,名称为IndexActiveDataFilter;
2、具体代码实现:

<?php
namespace app\models;

use yii\base\InvalidConfigException;
use yii\data\ActiveDataFilter;
use Yii;

class IndexActiveDataFilter extends ActiveDataFilter
{

    /**
     * 新增字段查询映射,具体参数可参考 filterControls
     * 比如要设定username的like查询
     * ['username' => 'like']
     * 若不设定某个查询属性,则使用默认值,系统中会自动解析
     * @var array
     */
    public array $fieldFilterControls = [];

    public function init()
    {
        parent::init();
        $request = Yii::$app->getRequest();
        $requestParams = $request->getBodyParams() ?: $request->getQueryParams();
        $this->prepareFilter($requestParams);
    }

    /**
     * 该方法会对$this->filterAttributeName对目标过滤值'filter'填充
     * 如同在load()执行后,填充$this->filterAttributeName一样;
     * 在逻辑上对处理,该方法会获取参数进行填充,依旧受到searchModel对规则限制,在此处不做合法性验证,
     * 因为在后面对build方法执行时,会自动验证,这时yii2框架自带的功能;
     * 如果有传递filter[field]=?类似的过滤条件,会自动覆盖原有的值,即filter的权重更高;
     * @throws InvalidConfigException
     */
    protected function prepareFilter($data = []): array
    {
        $model = $this->getSearchModel();
        $model->load($data, '');

        $filter= [];
        $attrs = $model->getAttributes();
        foreach ($attrs as $attr => $value) {
            if (null === $value) {
                continue;
            }
            if (isset($this->fieldFilterControls[$attr])) {
                $control = $this->fieldFilterControls[$attr];
                $filter[$attr] = [$control => $value];
            } else {
                $filter[$attr] = $value;
            }
        }
        return $this->{$this->filterAttributeName} = $filter;
    }
}

我们假定搜索用户表的两个字段usernamestatus,使用代码如下:

<php
namespace app\controllers;
use yii\rest\ActiveController;

class UserController extends ActiveController
{
   public $modelClass = app\modles\User::class;

   public function actions(): array
   {
       $actions = parent::actions();
       $model = (new DynamicModel([
            'username', 'status'
       ]))->addRule(['username'], 'filter', ['filter' => 'trim', 'skipOnArray' => true])
        ->addRule('username', 'string', ['min' => 2, 'max' => 30])
        ->addRule('status', 'in', ['range' => [0, 1]]);

        $actions['index']['dataFilter'] = [
            'class' => IndexActiveDataFilter::class,
            'searchModel' => $model,
            // 本次新增的属性,用于设定组成Query的查询方式
            'fieldFilterControls' => [
            // 如果username不设定,则系统会自动判断
            'username' => 'like',
            // status设定为eq,表示'=';
            //若该参数以stats[]=0&status[]=1传入,该值则应为'in',表示数组查询;
            'status' => 'eq'
        ]
   ];

   return $actions;
   }
}

按以上操作,即完成了参数传递方式的改写;
注意:
1、系统中的 fitler[username][like]=yii 的方式并未改变;
2、get 参数和 filter 中具有同样的 key,比如,都传入了 username,则以 fitler 中的为准;
3、其他的未可见风险,暂时没有发现;

若有什么错误,请指出!
谢谢阅读!

    没有找到数据。
您需要登录后才可以评论。登录 | 立即注册