laravel:检查一个关系中是否存在所有值

f45qwnt8  于 2021-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(242)

我和你之间有一种多对多的关系 User 以及 Role 并希望检查用户是否具有给定列表中的任何角色。
所以我在模型上输入:

public function hasAnyRoles(array $roles) {
    return $this->roles()->whereIn('name', $roles)->exists();
}

继续 UserController :

// User has only "manager" role.
$user->hasAnyRoles(['admin', 'manager']) // true

问题是,在某些部分,我需要验证用户是否拥有给定列表中的所有角色。例如:

// User has only "manager" role.
$user->hasRoles(['admin', 'manager']) // false

我是用“懒惰”的方式写的,这会产生 n + 1 查询:

public function hasRolesLazy($roles) {
    return array_reduce($roles, function ($initial, $role) {
        return $this->roles()->where('name', $role)->exists();
    }, false);
}

怎样 hasRoles(array $roles) 方法必须构造为只执行数据库中的一个查询?我是sql的新手,所以我想不出多少解决方案。

kmbjn2e3

kmbjn2e31#

试试这个:

public function hasAnyRoles(array $roles) {
    return $this->whereHas('roles', function ($query) use ($roles) {
         return $query->whereIn('name', $roles);
    })->isNotEmpty();
}
lnxxn5zx

lnxxn5zx2#

我的建议是,一旦使用关系,就为用户加载所有角色。当您通过像属性一样调用关系来加载关系时,laravel会将其缓存在引擎盖下,这样它就不会重复任何查询。然后,您可以简单地使用加载的角色来实现两种方法:

public function hasAnyRoles(array $roles)
{
    // When you call $this->roles, the relationship is cached. Run through
    // each of the user's roles.
    foreach ($this->roles as $role) {
        // If the user's role we're looking at is in the provided $roles
        // array, then the user has at least one of them. Return true.
        if (in_array($role->name, $roles) {
            return true;
        }
    }

    // If we get here, the user does not have any of the required roles. 
    // Return false.
    return false;
}

第二种方法是:

public function hasRoles(array $roles)
{
    // Run through each of the roles provided, that the user MUST have
    foreach ($roles as $role) {
        // Call the $this->roles relationship, which will return a collection
        // and be cached. Find the first role that has the name of the role
        // we're looking at.
        $found = $this->roles->first(function ($r) use ($role) {
            return $r->name == $role;
        });

        // If a role could not be found in the user's roles that matches the
        // one we're looking, then the user does not have the role, return 
        // false
        if (!$found) {
            return false;
        }
    }

    // If we get here, the user has all of the roles provided to the method
    return true;
}

当然,有许多不同的方法来实现这些方法,特别是在 Collection 类将帮助您,但关键是使用 $this->roles 只产生一个查询。

相关问题