You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii2.0.15搜索模型问题:多模型组合与Query替代ActiveRecord

刚好做过类似的需求,给你梳理一套完整的实现方案!既然你打定主意不用ActiveRecord,全靠new Query()来写查询,那咱们就围绕多模型关联+搜索模型的思路来搞定这个GridView的搜索功能。

第一步:创建多模型搜索模型

首先咱们在models目录下新建一个搜索模型,比如叫UserStoreSearch.php,这个模型不用继承ActiveRecord,只需要继承yii\base\Model就行,因为咱们全程用Query来拼SQL。

<?php
namespace app\models;

use yii\base\Model;
use yii\data\ActiveDataProvider;
use yii\db\Query;

class UserStoreSearch extends Model
{
    // 对应GridView的5个字段
    public $role; // 用户职位/角色
    public $storeName; // 门店名称
    public $brand; // 品牌
    public $representativeCode; // 代表编号
    public $provinceCity; // 省市

    /**
     * 验证规则(搜索用,只要安全即可)
     */
    public function rules()
    {
        return [
            [['role', 'storeName', 'brand', 'representativeCode', 'provinceCity'], 'safe'],
        ];
    }

    /**
     * 核心搜索方法,返回DataProvider
     */
    public function search($params)
    {
        // 初始化Query,关联需要的表
        $query = (new Query())
            ->select([
                'user.id', // 保留用户ID方便后续操作
                'auth_assignment.item_name AS role', // 从RBAC表取角色作为职位
                'store.name AS storeName',
                'store.brand',
                'store.representative_code AS representativeCode',
                'store.province_city AS provinceCity'
            ])
            ->from('user')
            // 关联RBAC的角色分配表,获取用户角色
            ->leftJoin('auth_assignment', 'user.id = auth_assignment.user_id')
            // 关联门店表(这里假设你的门店表叫`store`,且user表有`store_id`字段关联门店ID)
            ->leftJoin('store', 'user.store_id = store.id');

        // 创建DataProvider
        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'pagination' => [
                'pageSize' => 20, // 自定义每页条数
            ],
            'sort' => [
                // 配置排序规则,对应你的字段
                'attributes' => [
                    'role' => ['asc' => ['auth_assignment.item_name' => SORT_ASC], 'desc' => ['auth_assignment.item_name' => SORT_DESC]],
                    'storeName' => ['asc' => ['store.name' => SORT_ASC], 'desc' => ['store.name' => SORT_DESC]],
                    'brand',
                    'representativeCode',
                    'provinceCity'
                ]
            ],
        ]);

        // 加载搜索参数,如果没传参数直接返回默认列表
        if (!$this->load($params) && $params) {
            return $dataProvider;
        }

        // 添加过滤条件
        // 角色过滤(精确匹配,因为RBAC角色是固定值)
        if (!empty($this->role)) {
            $query->andWhere(['auth_assignment.item_name' => $this->role]);
        }

        // 门店名称模糊搜索
        if (!empty($this->storeName)) {
            $query->andFilterWhere(['like', 'store.name', $this->storeName]);
        }

        // 品牌模糊搜索
        if (!empty($this->brand)) {
            $query->andFilterWhere(['like', 'store.brand', $this->brand]);
        }

        // 代表编号精确/模糊搜索,看你的需求
        if (!empty($this->representativeCode)) {
            $query->andFilterWhere(['like', 'store.representative_code', $this->representativeCode]);
            // 如果是精确匹配就改成:->andWhere(['store.representative_code' => $this->representativeCode]);
        }

        // 省市模糊搜索
        if (!empty($this->provinceCity)) {
            $query->andFilterWhere(['like', 'store.province_city', $this->provinceCity]);
        }

        return $dataProvider;
    }
}
第二步:控制器里调用搜索模型

在你的控制器(比如StoreController)的actionIndex方法里,实例化搜索模型,传入请求参数,拿到DataProvider传给视图:

public function actionIndex()
{
    $searchModel = new \app\models\UserStoreSearch();
    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

    return $this->render('index', [
        'searchModel' => $searchModel,
        'dataProvider' => $dataProvider,
    ]);
}
第三步:配置GridView和搜索表单

在视图index.php里,先写搜索表单,然后是GridView:

搜索表单部分

先添加表单引用:

<?php echo $this->render('_search', ['model' => $searchModel]); ?>

然后新建_search.php视图,放搜索表单:

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\models\UserStoreSearch */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="user-store-search">

    <?php $form = ActiveForm::begin([
        'action' => ['index'],
        'method' => 'get',
        'options' => [
            'data-pjax' => 1
        ],
    ]); ?>

    <?= $form->field($model, 'role')->dropDownList([
        // 这里可以从RBAC的auth_item表动态获取,或者硬编码你的角色
        'finance_manager' => '财务经理',
        'representative' => '代表',
        'visitor' => '访客',
        'store_admin' => '门店管理员',
    ], ['prompt' => '请选择角色']) ?>

    <?= $form->field($model, 'storeName') ?>

    <?= $form->field($model, 'brand') ?>

    <?= $form->field($model, 'representativeCode') ?>

    <?= $form->field($model, 'provinceCity') ?>

    <div class="form-group">
        <?= Html::submitButton('搜索', ['class' => 'btn btn-primary']) ?>
        <?= Html::resetButton('重置', ['class' => 'btn btn-outline-secondary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

GridView部分

<?= \yii\grid\GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],

        // 对应搜索模型里的属性
        [
            'attribute' => 'role',
            'label' => '用户职位',
            'value' => function($model) {
                // 把角色值转成中文名称
                $roleMap = [
                    'finance_manager' => '财务经理',
                    'representative' => '代表',
                    'visitor' => '访客',
                    'store_admin' => '门店管理员',
                ];
                return $roleMap[$model['role']] ?? $model['role'];
            }
        ],
        [
            'attribute' => 'storeName',
            'label' => '门店名称',
        ],
        [
            'attribute' => 'brand',
            'label' => '品牌',
        ],
        [
            'attribute' => 'representativeCode',
            'label' => '代表编号',
        ],
        [
            'attribute' => 'provinceCity',
            'label' => '省市',
        ],

        // 操作列,如果需要的话
        ['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>
一些注意事项
  • 表名和关联字段要根据你实际的数据库结构调整,比如门店表如果不叫store,或者用户和门店的关联字段不是store_id,要对应修改Query里的关联条件。
  • 如果一个用户有多个RBAC角色,auth_assignment会有多条记录,这时候查询会出现重复数据,你可以在Query里加->distinct()去重,或者根据业务逻辑取主要角色。
  • 角色下拉框的选项,你也可以动态从auth_item表获取,比如用(new Query())->select(['name', 'name'])->from('auth_item')->where(['type' => 1])->indexBy('name')->column(),这样不用硬编码角色。

内容的提问来源于stack exchange,提问作者MHF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:50:08