来源:How to display, sort, and filter related model data in GridView
我想分享如何处理相关的模型显示数据表格中的数据。开始,我们实际上有两种情况需要考虑。让我们用以下三个表来演示:
表结构如下:
tbl_user: id, role_id, email, username, etc
tbl_role: id, name
tbl_profile: id, user_id, full_name
从这三个表,您可以看到用户所属角色和配置文件。
根据 belongs to/has
关系,我们会做不同的事情。下面是示例,我们将tbl_role.name
和 tbl_profile.full_name
一起显示到GridView。
1、在视图中显示数据文件
文件: app/views/user/index.php
<?php echo \yii\grid\GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// 其他列
[
'attribute' => 'full_name',
'label' => 'Full Name',
'value' => function($model, $index, $dataColumn) {
return $model->profile->full_name;
}
],
[
'attribute' => 'role_id',
'label' => 'Role',
'filter' => Role::dropdown(),
'value' => function($model, $index, $dataColumn) {
// more optimized than $model->role->name;
$roleDropdown = Role::dropdown();
return $roleDropdown[$model->role_id];
},
],
// 其他列
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
文件: app/models/Role.php
public static function dropdown() {
$models = static::find()->all();
foreach ($models as $model) {
$dropdown[$model->id] = $model->name;
}
return $dropdown;
}
太棒了!信不信由你,但这是我们所需要的信息的作用。完成了,完成了。
下一步,让我们的工作概要信息。我们需要更新搜索模型(即$searchModel )。
2、将属性添加到模型中
文件:app/models/search/UserSearch.php (3个地方要改)
a) public $full_name;
b) public function rules() { } // 添加一条规则,以便它可以验证
c) public function attributeLabels() { } // 添加一个标签
3、修改搜索查询来处理新属性 文件:app/models/search/UserSearch.php
public function search($params)
{
// add the inner join
$query = User::find();
$query->innerJoin("tbl_profile", "tbl_user.id=tbl_profile.user_id");
$query->with("profile"); // 急切的负荷减少数量的查询
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// 添加额外的类属性
$addSortAttributes = ["full_name"];
foreach ($addSortAttributes as $addSortAttribute) {
$dataProvider->sort->attributes[$addSortAttribute] = [
'asc' => [$addSortAttribute => SORT_ASC],
'desc' => [$addSortAttribute => SORT_DESC],
'label' => $this->getAttributeLabel($addSortAttribute),
];
}
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// 最后添加 full_name 条件
$this->addCondition($query, 'id');
...
$this->addCondition($query, 'full_name', true);
}
文件:app/models/search/UserSearch.php
protected function addCondition($query, $attribute, $partialMatch = false)
{
$value = $this->$attribute;
if (trim($value) === '') {
return;
}
// 添加表名与profile.id id来避免模棱两可的错误,
// 即, "tbl_user.id"
if ($attribute == "id") {
$attribute = "tbl_user.id";
}
if ($partialMatch) {
$query->andWhere(['like', $attribute, $value]);
} else {
$query->andWhere([$attribute => $value]);
}
}
我们现在有一个完整的网格与排序和过滤我们的相关模型。
但是,等等,如果我们有很多角色吗?我们怎么做如果下拉列表太大,我们需要寻找的名字吗?
好的,那么我们需要将它转换成一个文本搜索。这意味着我们不再使用role_id
,而是role_name
。所以让我们继续,改变在我们的所有实例的代码。
4、在视图中更新数据文件
文件:app/views/user/index.php
[
'attribute' => 'role_name',
'label' => 'Role',
// 删除下拉过滤器返回文本
//'filter' => Role::dropdown(),
'value' => function($model, $index, $dataColumn) {
// more optimized than $model->role->name;
$roleDropdown = Role::dropdown();
return $roleDropdown[$model->role_id];
},
],
然后我们需要回到搜索模型。
5、更新模型中的属性
文件: app/models/search/UserSearch.php (3个地方要改)
a) public $role_name; // $role_id 改成 $role_name
b) public function rules() { } // 'role_id' 改成 'role_name', int 改成 string
c) public function attributeLabels() { } // 'role_id' 改成 'role_name'
6、修改搜索查询来处理新属性
文件: app/models/search/UserSearch.php
public function search($params)
{
// 都添加内连接
$query = User::find();
$query->innerJoin("tbl_profile", "tbl_user.id=tbl_profile.user_id");
$query->innerJoin("tbl_role", "tbl_user.role_id=tbl_role.id");
$query->with("profile"); // 急切的负荷减少数量的查询
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// 更新为 role_id->role_name 排序
$dataProvider->sort->attributes["role_name"]["asc"] = ["tbl_role.name" => SORT_ASC];
$dataProvider->sort->attributes["role_name"]["desc"] = ["tbl_role.name" => SORT_DESC];
$dataProvider->sort->attributes["role_name"]["label"] = "Role";
// 添加额外的类属性
$addSortAttributes = ["full_name"];
foreach ($addSortAttributes as $addSortAttribute) {
$dataProvider->sort->attributes[$addSortAttribute] = [
'asc' => [$addSortAttribute => SORT_ASC],
'desc' => [$addSortAttribute => SORT_DESC],
'label' => $this->getAttributeLabel($addSortAttribute),
];
}
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// 修改 addCondition,role_id->role_name 部分匹配
$this->addCondition($query, 'id');
...
//$this->addCondition($query, 'role_id'); // 替换为“role_name”
$this->addCondition($query, 'role_name', true);
...
}
7、修改addCondition role_name 转换成适当的 sql 函数
文件:app/models/search/UserSearch.php
protected function addCondition($query, $attribute, $partialMatch = false)
{
$value = $this->$attribute;
if (trim($value) === '') {
return;
}
// 添加表名与profile.id id来避免模棱两可的错误,
// 即, "tbl_user.id"
if ($attribute == "id") {
$attribute = "tbl_user.id";
}
// 为 "role_name" 转换为 "tbl_role.name"
elseif ($attribute == "role_name") {
$attribute = "tbl_role.name";
}
if ($partialMatch) {
$query->andWhere(['like', $attribute, $value]);
} else {
$query->andWhere([$attribute => $value]);
}
}
好了,我们现在有一个可搜索文本框的角色。
视图部分可以有更简洁的写法
<?php echo \yii\grid\GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// 其他列
[
'attribute' => 'full_name',
'label' => 'Full Name',
//此处如果确定是关联对象的话可以这么写
'value' => 'profile.full_name'
],
[
'attribute' => 'role_id',
'label' => 'Role',
'filter' => Role::dropdown(),
'value' => function($model, $index, $dataColumn) {
// more optimized than $model->role->name;
$roleDropdown = Role::dropdown();
return $roleDropdown[$model->role_id];
},
],
// 其他列
['class' => 'yii\grid\ActionColumn'],
],
]); ?>