hasManyThrough 与变形

hasManyThrough with morph

我有一个项目 table 可以分配给用户或团队,这是结构:

id
assignable_id
assignable_type

class Project extends Model {
    public function assignable(): MorphTo
    {
        return $this->morphTo();
    }
}

我的团队 table 包含具有关键点的成员 table:

id

class Team extends Model {

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class);
    }

    public function projects(): MorphMany
    {
        return $this->morphMany(Project::class, 'assignable');
    }
}

// team_user table
team_id
user_id

最后是我的用户 table:

id

class User extends Model {

    public function teams(): BelongsToMany
    {
        return $this->belongsToMany(Team::class);
    }

    public function projects(): MorphMany
    {
        return $this->morphMany(Project::class, 'assignable');
    }
}

现在的问题是我想得到所有直接或通过团队分配给用户的项目,正如预期的那样 $user()->projects return 直接分配的项目给用户。

我尝试了很多解决方案,但 none 对我有用。

所以你实际上需要这样的东西:

public function project()
{
    return $this->hasManyThrough('App\Project', 'App\User', 'assignable_id')
        ->where(
            'assignable_type', 
            array_search(static::class, Relation::morphMap()) ?: static::class
        );
}

public function project()
{
    return $this->belongsToMany(Project::class, 'assignable', 'assignable_id', 'project_id')
        ->where('assignable_type', static::class);
}

参考:Laravel Polymorphic Relations Has Many Through

您的工作解决方案:

public function projects() {
    return $this->hasManyThrough(
        Project::class,
        User::class,
        'id',
        'assignable_id',
    )->where(
        'assignable_type', User::class
    )->orWhere(function ($q) {
        $q->where('assignable_type', Team::class)
        ->whereIn('assignable_id', $this->teams->pluck('id'));
    });
}

使用whereHasMorph:

$user = ...

$projects = Project::whereHasMorph(
    'assignable',
    [Team::class, User::class],
    function ($query, $type) use($user) {
        if($type === Team::class){
            $query->whereRelation('users', 'id', $user->id);
        }else{
            $query->where('id', $user->id);
        } 
    }
)->get();

或拆分成 2 个查询并合并在一起:

$projects = $user->projects;
$teams = $user->teams()->with('projects')->get();
$teams_projects = $teams->pluck('projects')->collapse();
$projects = $projects->merge($teams_projects);