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
相关产品推荐
相关产品推荐

