PHP, Yii2 Фильтрация GridView по реляционной ценности
После этого:
Yii2 Как работает поиск() в 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
, нажав на ссылку заголовка`. Любая помощь будет оценена по достоинству. Спасибо.
Ответы
Ответ 1
Фильтрация сетки в столбце прост в 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",
],
Ответ 2
Это основано на описании в руководстве. Базовый код для 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 */
]
]);
Ответ 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'],
],
]); ?>
Буду признателен за любые критические замечания и советы.