You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:48:32