Фильтрация PHP, Yii2 GridView по реляционному значению

Исходя из этого:

Yii2, как работает search() в SearchModel?

Я хотел бы иметь возможность фильтровать столбец GridView реляционных данных. Это то, что я имею в виду:

У меня есть две таблицы, TableA и TableB. У обоих есть соответствующие модели, сгенерированные с помощью Gii. TableA имеет внешний ключ для значения в TableB, например:

TableA
attrA1, attrA2, attrA3, TableB.attrB1

TableB
attrB1, attrB2, attrB3

attrA1 и attrB1 являются первичными ключами соответствующих им таблиц.

Теперь у меня есть Yii2 GridView из attrA2, attrA3 и attrB2. У меня есть рабочий фильтр для attrA2 и attrA3, так что я могу выполнять поиск по значениям столбцов. У меня также есть рабочая сортировка для этих двух столбцов - просто щелкнув заголовок столбца. Я хотел бы иметь возможность добавить эту фильтрацию и сортировку и на 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 где-то в моей функции поиска, но я не уверен, как это сделать. Точно так же я хотел бы иметь возможность сортировать и по этому столбцу - точно так же, как я могу для attrA2 и AttrA3, щелкнув ссылку в заголовке`. Любая помощь будет оценена по достоинству. Спасибо.


person Mr Goobri    schedule 24.02.2014    source источник
comment
Не могли бы вы обновить свой вопрос, чтобы searchModel отражал последние изменения в структуре.   -  person Paul van Schayck    schedule 09.04.2014


Ответы (3)


Фильтровать gridview по столбцу в Yii 2.0 чертовски просто. Добавьте атрибут фильтра в столбец 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",
], 
person iltaf khalid    schedule 26.01.2015
comment
Только что увидел это, год спустя и 2 года с тех пор, как я спросил об этом. Это аккуратный маленький ответ и, безусловно, самое простое решение. Спасибо. - person Mr Goobri; 01.08.2016
comment
это хорошо и работает для меня, но все приводит к DropDownList, как изменить текстовое поле ajax, например больше текстового поля фильтра ??? - person user3770797; 24.07.2017

Это основано на описании в руководстве. Базовый код для 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 */        
     ]
]);
person Paul van Schayck    schedule 09.04.2014
comment
$query->joinWith(['companyPosition']); должно быть $query->joinWith(['TableB']); - person pedak; 27.11.2014
comment
Отличный ответ, спасибо, но со временем Yii2 развился, и я перераспределил решение на более простые ответы. Ваше здоровье. - person Mr Goobri; 01.08.2016
comment
Я добавил это, чтобы игнорировать регистр символов: $query->andFilterWhere([ 'like', 'LOWER(TableB.attrB1)', strtolower($this->getAttribute('TableB.attrB1')) ]); - person Ahmed Ismail; 07.07.2019

Я тоже застрял с этой проблемой, и мое решение несколько отличается. У меня есть две простые модели:

Книга:

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

Буду признателен за любую критику и советы.

person Alex    schedule 22.04.2014