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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 06:45:33