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

Laravel Eloquent:为Post模型追加当前用户是否点赞的is_liked字段

嘿,这个需求我熟得很,给你几个Laravel里优雅的实现方案,按需选就行:

方案1:使用Eloquent的withExists方法(推荐)

这是Laravel 5.8+支持的特性,专门用来判断关联是否存在,代码最简洁,还不会有N+1查询问题。

首先得确保你的Post模型里的多态关联配置正确:

// app/Models/Post.php
public function likes()
{
    return $this->morphMany(Like::class, 'likable');
}

然后查询的时候直接用withExists,还能自定义字段名称为is_liked:

$posts = Post::query()
    // 仅当用户登录时才判断点赞状态
    ->when(auth()->check(), function($query) {
        $query->withExists([
            'likes as is_liked' => function($q) {
                $q->where('user_id', auth()->id());
            }
        ]);
    })
    // 未登录用户直接返回is_liked为false
    ->when(!auth()->check(), function($query) {
        $query->selectRaw('posts.*, 0 as is_liked');
    })
    ->get();

这样每个Post实例里都会有一个布尔类型的is_liked字段,直接就能用在前端展示啦。

方案2:添加模型访问器

如果不想在查询语句里额外处理,也可以在Post模型里加一个访问器,自动计算is_liked状态:

// app/Models/Post.php
// 把is_liked自动追加到模型的数组/JSON输出中
protected $appends = ['is_liked'];

public function getIsLikedAttribute()
{
    // 未登录直接返回false
    if (!auth()->check()) {
        return false;
    }
    // 判断当前用户是否给该帖子点过赞
    return $this->likes()->where('user_id', auth()->id())->exists();
}

之后直接调用Post::get()就能拿到带is_liked的集合了。不过要注意:如果一次性获取大量帖子,这种方式会触发N+1查询,数据量大的话建议搭配with('likes')预加载,或者直接用方案1。

方案3:手动添加子查询(兼容老版本Laravel)

如果你用的是低于5.8的Laravel版本,不支持withExists,可以手动用子查询实现:

$userId = auth()->id();

$posts = Post::query()
    ->when(auth()->check(), function($query) use ($userId) {
        $query->addSelect([
            'is_liked' => Like::selectRaw('1')
                ->whereColumn('likable_id', 'posts.id')
                ->where('likable_type', Post::class)
                ->where('user_id', $userId)
                ->limit(1)
        ]);
    })
    ->when(!auth()->check(), function($query) {
        $query->selectRaw('posts.*, 0 as is_liked');
    })
    ->get();

// 把子查询返回的null转为false
$posts->each(function($post) {
    $post->is_liked = !is_null($post->is_liked);
});

额外注意点

  • 确保likes表的likable_type存储的是正确的模型类名(比如App\Models\Post),如果存的是短类名,要在Post模型里设置protected $morphClass = 'Post';
  • 性能优先的话,方案1和3都是单次查询,比方案2更适合数据量大的场景

内容的提问来源于stack exchange,提问作者senty

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:17:24