PHP,Yii2 GridView关于关联值的过滤

19

接着上面的问题:

Yii2中SearchModel中的search()方法是如何工作的?

我希望能够过滤一个关联数据列的GridView。具体来说:

我有两个表,TableATableB。两个表都使用Gii生成了对应的模型。 TableA有一个外键指向TableB的一个值,就像这样:

TableA
attrA1, attrA2, attrA3, TableB.attrB1

TableB
attrB1, attrB2, attrB3

attrA1和attrB1是它们对应表格的主键。

现在我有一个Yii2的GridView,包括attrA2attrA3attrB2。我已经可以筛选attrA2attrA3进行列值搜索,并且这两列也支持排序——只需点击列头即可。我希望能够在attrB2上添加筛选和排序功能。

我的TableASearch模型如下:

public function search($params){
    $query = TableA::find();
    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]);

    if (!($this->load($params) && $this->validate())) {
        return $dataProvider;
    }

    $this->addCondition($query, 'attrA2');
    $this->addCondition($query, 'attrA2', true);
    $this->addCondition($query, 'attrA3');
    $this->addCondition($query, 'attrA3', true);

    return $dataProvider;
}

在我的TableA模型中,我设置相关的值如下:

    public $relationalValue;

public function afterFind(){
    $b = TableB::find(['attrB1' => $this->attrB1]);
    $this->relationalValue = $b->relationalValue;
}

虽然这可能不是最佳实践,但我认为我必须在我的搜索函数中使用$relationalValue,但我不确定如何做。同样地,我想能够通过点击标题链接来按此列排序-就像我可以为attrA2AttrA3做到的那样。任何帮助将不胜感激。谢谢。


你能否更新你的问题,让searchModel反映出框架的最新变化。 - Paul van Schayck
3个回答

24
这是基于指南中的描述。SearchModel 的基础代码来自 Gii 代码生成器。这也假设 $this->TableB 已经使用 hasOne() 或 hasMany() 关系进行设置。请参阅文档
1. 设置搜索模型
在 TableASearch 模型中添加:
public function attributes()
{
    // add related fields to searchable attributes
    return array_merge(parent::attributes(), ['TableB.attrB1']);
}

public function rules() 
{
    return [
        /* your other rules */
        [['TableB.attrB1'], 'safe']
    ];
}

然后在TableASearch->search()中添加以下内容(在$this->load()之前):

$dataProvider->sort->attributes['TableB.attrB1'] = [
      'asc' => ['TableB.attrB1' => SORT_ASC],
      'desc' => ['TableB.attrB1' => SORT_DESC],
 ];

$query->joinWith(['TableB']); 

接下来是对数据进行实际搜索(在$this->load()下方):

$query->andFilterWhere([
    'like',
    'TableB.attrB1',
     $this->getAttribute('TableB.attrB1')
]);

2. 配置 GridView

将以下内容添加到您的视图中:

echo GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        /* Other columns */
       'TableB1.attrB1',
        /* Other columns */        
     ]
]);

$query->joinWith(['companyPosition']); 应该改为 $query->joinWith(['TableB']); - pedak
非常好的答案,谢谢。但是随着时间的推移,Yii2已经发生了变化,我已经将“解决方案”重新分配给了更简单的答案。干杯。 - Mr Goobri
我添加了以下内容以忽略字符大小写: 'like', 'LOWER(TableB.attrB1)', strtolower($this->getAttribute('TableB.attrB1')) ]); ``` - Ahmed Ismail

5

在Yii 2.0中,通过列过滤gridview非常容易。请按以下方式将filter属性添加到具有查找值的gridview列中:

[
        "class" => yii\grid\DataColumn::className(),
        "attribute" => "status_id",
        'filter' => ArrayHelper::map(Status::find()->orderBy('name')->asArray()->all(), 'id', 'name'),
        "value" => function($model){
            if ($rel = $model->getStatus()->one()) {
                return yii\helpers\Html::a($rel->name,["crud/status/view", 'id' => $rel->id,],["data-pjax"=>0]);
            } else {
                return '';
            }
        },
        "format" => "raw",
], 

刚看到这个,已经过去一年了,距离我提出问题已经两年了。这是一个简洁的答案,也是最简单的解决方案。谢谢。 - Mr Goobri
这个代码对我来说很好用,但是所有的结果都在下拉列表中显示,如何将Ajax文本框更改为更多的筛选文本框呢? - user3770797

3
我也遇到了这个问题,我的解决方案有所不同。我有两个简单的模型:
书:
class Book extends ActiveRecord
{
    ....

    public static function tableName()
    {
        return 'books';
    }

    public function getAuthor()
    {
        return $this->hasOne(Author::className(), ['id' => 'author_id']);
    }

作者:

class Author extends ActiveRecord
{

    public static function tableName()
    {
        return 'authors';
    }

    public function getBooks()
    {
        return $this->hasMany(Book::className(), ['author_id' => 'id']);
    }

但是我的搜索逻辑在不同的模型中。我没有找到如何在不创建额外字段“author_first_name”的情况下实现搜索。因此,这是我的解决方案:
class BookSearch extends Model
{
    public $id;
    public $title;
    public $author_first_name;

    public function rules()
    {
        return [
            [['id', 'author_id'], 'integer'],
            [['title', 'author_first_name'], 'safe'],
        ];
    }

    public function search($params)
    {
        $query = Book::find()->joinWith(['author' => function($query) { $query->from(['author' => 'authors']);}]);
        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'pagination' => array('pageSize' => 50),
            'sort'=>[
                'attributes'=>[
                    'author_first_name'=>[
                        'asc' => ['author.first_name' => SORT_ASC],
                        'desc' => ['author.first_name' => SORT_DESC],
                    ]
                ]
            ]
        ]);

        if (!($this->load($params) && $this->validate())) {
            return $dataProvider;
        }
        ....
        $query->andWhere(['like', 'author.first_name', $this->author_first_name]);
        return $dataProvider;
    }
}

这是用于创建表别名的代码:function($query) { $query->from(['author' => 'authors']);} 而GridView的代码是:
<?php echo GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        [
            'attribute' => 'id',
            'filter' => false,
        ],
        [
            'attribute' => 'title',
        ],
        [
            'attribute' => 'author_first_name',
            'value' => function ($model) {
                    if ($model->author) {
                        $model->author->getFullName();
                    } else {
                        return '';
                    }
                },
            'filter' => true,
        ],
        ['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>

我会感激任何批评和建议。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接