web-dev-qa-db-ja.com

PHP、Yii2リレーショナル値でのGridViewフィルタリング

これから続く:

Yii2 SearchModelのsearch()はどのように機能しますか?

リレーショナルデータのGridView列をフィルタリングできるようにしたいと思います。これは私が意味することです:

TableATableBの2つのテーブルがあります。どちらにも、Giiを使用して生成された対応するモデルがあります。 TableAには、次のようにTableBの値への外部キーがあります。

TableA
attrA1, attrA2, attrA3, TableB.attrB1

TableB
attrB1, attrB2, attrB3

attrA1とattrB1は、対応するテーブルの主キーです。

これで、Yii2 GridViewattrA2attrA3attrB2になりました。列の値を検索できるように、attrA2attrA3に有効なフィルターがあります。また、列ヘッダーをクリックするだけで、これら2つの列の作業ソートもできます。このフィルタリングと並べ替えを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でできるのと同じです。任意の助けいただければ幸いです。ありがとう。

17
Mr Goobri

Yii 2.0では、列でグリッドビューをフィルタリングするのはとても簡単です。以下のように、ルックアップ値を持つグリッドビュー列にフィルター属性を追加してください:

[
        "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",
], 
4
iltaf khalid

これは ガイド の説明に基づいています。 SearchModelの基本コードは、Giiコードジェネレーターから取得されます。これは、$ this-> TableBがhasOne()またはhasMany()リレーションを使用して設定されていることも前提としています。これを見てください doc

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 */        
     ]
]);
_
21

私もこの問題に悩まされており、私の解決策はかなり異なります。 2つの単純なモデルがあります。

本:

_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'],
    ],
]); ?>
_

どんな批評やアドバイスにも感謝します。

3
Alex