Eloquent Many to Many选择没有特定角色的用户

Rif*_*fki 5 laravel eloquent laravel-5.2

所以,我有UserRole许多一对多的关系模型,我有3个角色:super,adminmoderator有4个用户,让我们说:John,Mike,JamesLarry.

Johnsuper,Mikeadminmoderator角色,Jamesadmin和,Larrymoderator.要显示没有特定角色的用户,我创建了此范围:

public function scopeDoesntHaveRoles($query, $roles = [], $column = 'id') {
    return $query->whereDoesntHave('roles')->orWhereHas('roles', function ($q) use ($roles, $column) {
        $q->whereNotIn($column, $roles);
    });
}
Run Code Online (Sandbox Code Playgroud)

当我打电话User::doesntHaveRoles([1])->lists('name', 'id')来获取没有super角色的用户时,它会起作用并返回:

{"2":"Mike","3":"James","4":"Larry"}
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试列出没有admin角色的用户时User::doesntHaveRoles([2])->lists('name', 'id'),肯定James没有在那里显示,但是Mike当他实际上有admin角色时出现了:

{"1":"John","2":"Mike","4":"Larry"}
Run Code Online (Sandbox Code Playgroud)

我认为这是因为Mike也有moderator角色,你在我的范围内看到了什么问题吗?或者你有其他解决方案吗?

谢谢

编辑: 这是我的枢轴架构

Schema::create('user_roles', function (Blueprint $table) {
    $table->integer('user_id')->unsigned();
    $table->integer('role_id')->unsigned();

    $table->primary([
        'user_id', 'role_id'
    ]);
});
Run Code Online (Sandbox Code Playgroud)

User 模型

public function roles()
{
    return $this->belongsToMany(Role::class, 'user_roles');
}
Run Code Online (Sandbox Code Playgroud)

Role 模型

public function users()
{
    return $this->belongsToMany(User::class, 'user_roles');
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*gel 2

我会用whereNotIn而不是whereDoesntHave.

给定Role存储在变量中的变量,$role您可以通过以下方式获取没有该角色的所有用户:

/* @var Role $role */
User::whereNotIn(function('id', $query) use ($role) {
    $query->select('user_id')
        ->from('user_roles')
        ->where('role_id', $role->id);
});
Run Code Online (Sandbox Code Playgroud)

内部查询将返回具有给定角色的用户的所有 ID。使用whereNotIn将返回相反的用户集。将创建以下查询:

select *
from users
where user_id not in (
    select user_id
    from user_roles
    where role_id = ?
);
Run Code Online (Sandbox Code Playgroud)

现在,Collection存储了一个角色,$roles您可以通过以下方式获取不具有任何该角色的所有用户:

/* @var Collection|Role[] $roles */
User::whereNotIn(function('id', $query) use ($roles) {
    $query->select('user_id')
        ->from('user_roles')
        ->whereIn('role_id', $roles->pluck('id');
});
Run Code Online (Sandbox Code Playgroud)

内部选择将返回具有集合中角色之一的所有用户的 ID。和whereNotIn你一起又会得到相反的结果。您还可以使用角色 ID 数组来代替$roles->pluck('id').

构建器将创建一个查询,例如

select *
from users
where user_id not in (
    select user_id
    from user_roles
    where role_id in (?, ?, ..)
);
Run Code Online (Sandbox Code Playgroud)