Laravel中获取模型关注者动态的查询返回空问题排查
问题分析与解决方案
核心问题诊断
你的代码存在两个关键错误,导致查询返回空结果:
1. 模型关联定义错误
关注关系是多态多对多关联,但你用了MorphMany(一对多多态)来定义followers关联,完全不符合followables表的多对多结构。该表同时存储follower和followable两个多态字段,必须用MorphToMany才能正确建立关联。
2. 查询作用域逻辑错误
pluck('followable_id', 'followable_type')生成的是键为followable_type、值为followable_id的集合,Laravel不支持将这种结构直接用于多字段whereIn查询。- 即便语法正确,原逻辑会错误地将
owner_id和owner_type分别与所有关注者的ID、类型做匹配,而非匹配对应的ID+类型组合,导致条件永远不满足。
修正步骤
第一步:修复User模型的关联关系
根据需求(获取当前用户关注的人发布的动态),正确定义followings关联(若需获取关注当前用户的人的动态,调整字段参数即可):
use Illuminate\Database\Eloquent\Relations\MorphToMany; class User extends Model { // 用户发布的动态 public function statuses(): MorphMany { return $this->morphMany(Status::class, 'owner'); } // 用户关注的人(多态多对多关联) public function followings(): MorphToMany { return $this->morphToMany( self::class, // 假设关注的是User模型,可按需替换 'followable', 'followables', // 关联表名 'follower_id', // 当前模型在关联表中的外键 'followable_id', // 关联目标模型在关联表中的外键 'id', // 当前模型的主键 'id' // 关联目标模型的主键 )->wherePivot('accepted_at', '!=', null); // 仅查询已通过的关注关系,可选 } // 若需获取关注当前用户的人,定义如下: public function followers(): MorphToMany { return $this->morphToMany( self::class, 'followable', 'followables', 'followable_id', // 目标模型外键改为当前用户ID 'follower_id', // 发起关注的用户ID 'id', 'id' )->wherePivot('accepted_at', '!=', null); } }
第二步:修复Status模型的查询作用域
推荐用whereExists或join实现关联查询,既高效又能保证ID+类型的匹配正确性:
方案一:使用whereExists(推荐,避免重复字段)
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\DB; class Status extends Model { public function scopeFollowings(Builder $query, Model $model): Builder { return $query->whereExists(function ($subquery) use ($model) { $subquery->select(DB::raw(1)) ->from('followables') // 匹配动态发布者与关注关系中的被关注者 ->whereColumn('followables.followable_id', 'statuses.owner_id') ->whereColumn('followables.followable_type', 'statuses.owner_type') // 指定发起关注的是当前用户 ->where('followables.follower_id', $model->id) ->where('followables.follower_type', get_class($model)) // 可选:仅查询已通过的关注 ->whereNotNull('followables.accepted_at'); }); } }
方案二:使用join
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; class Status extends Model { public function scopeFollowings(Builder $query, Model $model): Builder { return $query->join('followables', function ($join) use ($model) { $join->on('followables.followable_id', '=', 'statuses.owner_id') ->on('followables.followable_type', '=', 'statuses.owner_type') ->where('followables.follower_id', '=', $model->id) ->where('followables.follower_type', '=', get_class($model)) ->whereNotNull('followables.accepted_at'); })->select('statuses.*'); // 只选择动态表字段,避免关联表字段干扰 } }
使用示例
// 获取当前用户关注的人发布的所有动态 $user = User::find(1); $followingsStatuses = Status::followings($user)->get();
内容的提问来源于stack exchange,提问作者Nate
相关产品推荐
相关产品推荐

