Yii2技术问题:如何用单个筛选属性过滤多个数据属性?
Yii2 单个筛选属性过滤多个字段的解决方案
问题根源
ActiveDataFilter的attributeMap是关联数组,当你多次给同一个键(比如'detail')赋值时,后面的映射会直接覆盖前面的,最终只有最后一个字段会被应用到筛选条件中。
方法一:手动构建多字段OR筛选条件
直接获取前端传入的筛选参数,手动给查询添加多个字段的OR过滤规则,无需依赖attributeMap的重复映射:
// 初始化ActiveDataFilter $filter = new ActiveDataFilter([ 'searchModel' => 'app\models\YourModel', ]); // 获取detail筛选值 $filterParams = Yii::$app->request->get('filter', []); $detailValue = $filterParams['detail'] ?? null; if ($detailValue) { // 添加多个字段的模糊匹配OR条件 $query->orFilterWhere(['like', '{{classification}}.[[name]]', $detailValue]) ->orFilterWhere(['like', '{{subclass}}.[[name]]', $detailValue]); // 可继续追加更多需要匹配的字段 }
方法二:扩展ActiveDataFilter支持多字段映射
自定义继承自ActiveDataFilter的类,重写buildCondition方法,让attributeMap支持数组类型的值,自动生成OR条件组:
class MultiFieldActiveDataFilter extends \yii\data\ActiveDataFilter { protected function buildCondition($attribute, $operator, $value) { $fieldMap = $this->attributeMap[$attribute] ?? $attribute; // 若映射为数组,遍历生成OR条件 if (is_array($fieldMap)) { $conditions = []; foreach ($fieldMap as $field) { $conditions[] = [$operator, $field, $value]; } return ['or', ...$conditions]; } return parent::buildCondition($attribute, $operator, $value); } } // 使用扩展后的类 $filter = new MultiFieldActiveDataFilter([ 'searchModel' => 'app\models\YourModel', 'attributeMap' => [ 'detail' => [ '{{classification}}.[[name]]', '{{subclass}}.[[name]]', // 其他需要匹配的字段 ], ], ]); if ($filter->load(Yii::$app->request->get())) { $query->andFilterWhere($filter->build()); }
方法三:在Model的Search逻辑中处理虚拟属性
在业务Model中定义虚拟属性detail,然后在search方法中添加多字段的OR过滤规则:
1. 定义Model虚拟属性与关联关系
class YourModel extends \yii\db\ActiveRecord { // 虚拟属性,接收前端detail筛选值 public $detail; public function rules() { return array_merge(parent::rules(), [ [['detail'], 'safe'], // 标记为安全属性,允许接收参数 ]); } // 定义关联关系(按需添加) public function getClassification() { return $this->hasOne(Classification::class, ['id' => 'classification_id']); } public function getSubclass() { return $this->hasOne(Subclass::class, ['id' => 'subclass_id']); } }
2. 实现Search方法
public function search($params) { $query = self::find() ->joinWith(['classification', 'subclass']); // 关联需要筛选的表 $dataProvider = new \yii\data\ActiveDataProvider([ 'query' => $query, ]); // 加载参数并验证 $this->load($params); if (!$this->validate()) { return $dataProvider; } // 处理detail筛选的多字段OR条件 if ($this->detail) { $query->orFilterWhere(['like', 'classification.name', $this->detail]) ->orFilterWhere(['like', 'subclass.name', $this->detail]); } return $dataProvider; }
3. 控制器调用Search方法
public function actionIndex() { $searchModel = new YourModel(); $dataProvider = $searchModel->search(Yii::$app->request->queryParams); return $this->render('index', [ 'searchModel' => $searchModel, 'dataProvider' => $dataProvider, ]); }
内容的提问来源于stack exchange,提问作者Seto
相关产品推荐
相关产品推荐

