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
相关产品推荐
相关产品推荐

