Laravel:检查关系中是否存在所有值

时间:2018-01-16 20:42:26

标签: php mysql sql laravel

我在UserRole模型之间存在多对多的关系,并希望检查用户是否具有给定列表的任何角色。

所以我输入了模型:

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

我在" lazy"模式,生成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的新手,所以我无法找到很多解决方案。

2 个答案:

答案 0 :(得分:0)

试试这个:

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

答案 1 :(得分:0)

我的建议是,使用关系加载用户的所有角色。当您通过将其称为属性来加载关系时,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只会产生一个查询。