Yii2关联两张表查询未读政策并返回GridView结果
嘿,作为Yii2新手能快速对接需求真的不错!结合你用过oscom的经验,咱们一步步来实现这个「未读政策列表」的功能,核心就是做一个排除当前用户已读记录的查询,再用Yii2的GridView展示结果就行~
一、先给模型建立关联(关键前提)
首先得让Policy和Policyread模型之间建立关联,这样查询逻辑会更清晰。
- 在
Policy模型里添加关联方法,绑定当前用户的已读记录:
// models/Policy.php public function getPolicyread() { return $this->hasOne(Policyread::class, ['policy_id' => 'id']) ->where(['user_id' => Yii::$app->user->id]); // 只关联当前用户的已读数据 }
二、在PolicyController中编写未读政策查询逻辑
推荐在PolicyController里新建一个专门的actionUnread方法(避免和原有列表逻辑混淆):
// controllers/PolicyController.php public function actionUnread() { // 用NOT EXISTS子查询筛选未读政策:找所有没有被当前用户标记为已读的政策 $query = Policy::find() ->where(['not exists', Policyread::find() ->select('1') ->where(['policy_id' => new \yii\db\Expression('policy.id')]) ->andWhere(['user_id' => Yii::$app->user->id]) ]); // 构建数据提供者,给GridView用 $dataProvider = new \yii\data\ActiveDataProvider([ 'query' => $query, 'pagination' => [ 'pageSize' => 10, // 可根据需求调整每页显示条数 ], 'sort' => [ 'defaultOrder' => [ 'created_at' => SORT_DESC, // 按政策创建时间倒序,最新的排在前面 ], ], ]); return $this->render('unread', [ 'dataProvider' => $dataProvider, ]); }
这里用NOT EXISTS比左连接后判断null更高效,也更直观,适合新手理解维护。
三、创建GridView视图文件
在views/policy目录下新建unread.php,配置GridView展示未读政策,还可以加个「标记为已读」的按钮:
<?php use yii\grid\GridView; use yii\helpers\Html; $this->title = '我的未读政策'; $this->params['breadcrumbs'][] = $this->title; ?> <div class="policy-unread"> <h1><?= Html::encode($this->title) ?></h1> <?= GridView::widget([ 'dataProvider' => $dataProvider, 'columns' => [ ['class' => 'yii\grid\SerialColumn'], 'id', // 政策ID 'title', // 政策标题 'content:html', // 如果内容是富文本,用html格式渲染 'created_at:datetime', // 格式化显示创建时间 // 自定义「标记为已读」操作按钮 [ 'class' => 'yii\grid\ActionColumn', 'template' => '{mark-read}', 'buttons' => [ 'mark-read' => function ($url, $model) { return Html::a('标记为已读', ['policyread/create', 'policy_id' => $model->id], [ 'class' => 'btn btn-sm btn-success', 'data' => [ 'confirm' => '确定要标记该政策为已读吗?', 'method' => 'post', ], ]); }, ], ], ], ]); ?> </div>
四、完善PolicyreadController的创建逻辑
为了让「标记为已读」按钮正常工作,需要调整PolicyreadController的create方法,自动填充当前用户ID并避免重复标记:
// controllers/PolicyreadController.php public function actionCreate() { $model = new Policyread(); // 自动填充当前用户ID $model->user_id = Yii::$app->user->id; // 从请求中获取政策ID $model->policy_id = Yii::$app->request->get('policy_id'); // 尝试保存,利用模型的唯一验证避免重复标记 if ($model->save()) { Yii::$app->session->setFlash('success', '已标记为已读'); } else { Yii::$app->session->setFlash('error', '该政策已标记为已读'); } // 返回到未读政策列表页 return $this->redirect(Yii::$app->request->referrer ?: ['policy/unread']); }
别忘了在Policyread模型里添加唯一验证规则,防止同一用户重复标记同一政策:
// models/Policyread.php public function rules() { return [ [['policy_id', 'user_id'], 'required'], [['policy_id', 'user_id'], 'integer'], // 唯一验证:同一用户不能重复标记同一政策 [['policy_id', 'user_id'], 'unique', 'targetAttribute' => ['policy_id', 'user_id']], ]; }
内容的提问来源于stack exchange,提问作者Scot Henderson
相关产品推荐
相关产品推荐

