isForceDeleting()) { return; } $model->permissions()->detach(); }); } /** * A model may have direct permissions. */ public function permissions(): BelongsToMany { return $this->belongsToMany(Permission::class, 'role_has_permissions', 'role_id', 'permission_id'); } /** * Scope the model query to certain permissions only. * * @param \Illuminate\Database\Eloquent\Builder $query * @param string|array|Permission|Collection $permissions * * @return \Illuminate\Database\Eloquent\Builder */ public function scopePermission(Builder $query, $permissions): Builder { $permissions = $this->convertToPermissionModels($permissions); $rolesWithPermissions = array_unique(array_reduce($permissions, function ($result, $permission) { return array_merge($result, $permission->roles->all()); }, [])); return $query->where(function ($query) use ($permissions, $rolesWithPermissions) { $query->whereHas('permissions', function ($query) use ($permissions) { $query->where(function ($query) use ($permissions) { foreach ($permissions as $permission) { $query->orWhere('permissions.id', $permission->id); } }); }); if (count($rolesWithPermissions) > 0) { $query->orWhereHas('roles', function ($query) use ($rolesWithPermissions) { $query->where(function ($query) use ($rolesWithPermissions) { foreach ($rolesWithPermissions as $role) { $query->orWhere('roles.id', $role->id); } }); }); } }); } /** * @param string|array|Permission|Collection $permissions * * @return array */ protected function convertToPermissionModels($permissions): array { if ($permissions instanceof Collection) { $permissions = $permissions->all(); } $permissions = array_wrap($permissions); return array_map(function ($permission) { if ($permission instanceof Permission) { return $permission; } return app(Permission::class)->findByName($permission); }, $permissions); } /** * Determine if the model may perform the given permission. * * @param string|Permission $permission * @param string|null $guardName * * @return bool */ public function hasPermissionTo($permission): bool { if (is_string($permission)) { $permission = app(Permission::class)->findByName($permission); } if (is_int($permission)) { $permission = app(Permission::class)->findById($permission); } return $this->hasDirectPermission($permission) || $this->hasPermissionViaRole($permission); } /** * Determine if the model has any of the given permissions. * * @param array ...$permissions * * @return bool */ public function hasAnyPermission(...$permissions): bool { if (is_array($permissions[0])) { $permissions = $permissions[0]; } foreach ($permissions as $permission) { if ($this->hasPermissionTo($permission)) { return true; } } return false; } /** * Determine if the model has all of the given permissions. * * @param array ...$permissions * * @return bool */ public function hasAllPermissions(...$permissions): bool { if (is_array($permissions[0])) { $permissions = $permissions[0]; } foreach ($permissions as $permission) { if (! $this->hasPermissionTo($permission)) { return false; } } return true; } /** * Determine if the model has, via roles, the given permission. * * @param Permission $permission * * @return bool */ protected function hasPermissionViaRole(Permission $permission): bool { return $this->hasRole($permission->roles); } /** * Determine if the model has the given permission. * * @param string|Permission $permission * * @return bool */ public function hasDirectPermission($permission): bool { if (is_string($permission)) { $permission = app(Permission::class)->findByName($permission); if (!$permission) { return false; } } if (is_int($permission)) { $permission = app(Permission::class)->findById($permission); if (!$permission) { return false; } } return $this->permissions->contains('id', $permission->id); } /** * Return all the permissions the model has via roles. */ public function getPermissionsViaRoles(): Collection { return $this->load('roles', 'roles.permissions')->roles->flatMap(function ($role) { return $role->permissions; })->sort()->values(); } /** * Return all the permissions the model has, both directly and via roles. */ public function getAllPermissions(): Collection { return $this->permissions->merge($this->getPermissionsViaRoles())->sort()->values(); } /** * Grant the given permission(s) to a role. * * @param string|array|Permission|Collection $permissions * * @return $this */ public function givePermissionTo(...$permissions) { $permissions = collect($permissions)->flatten()->map(function ($permission) { return $this->getStoredPermission($permission); })->filter(function ($permission) { return $permission instanceof Permission; })->all(); $this->permissions()->saveMany($permissions); $this->forgetCachedPermissions(); return $this; } /** * Remove all current permissions and set the given ones. * * @param string|array|Permission|Collection $permissions * * @return $this */ public function syncPermissions(...$permissions) { return DB::transaction(function () use ($permissions) { $this->permissions()->detach(); return $this->givePermissionTo($permissions); }); } /** * Revoke the given permission. * * @param Permission|Permission[]|string|string[] $permission * * @return $this */ public function revokePermissionTo($permission) { $this->permissions()->detach($this->getStoredPermission($permission)); $this->forgetCachedPermissions(); return $this; } /** * @param string|array|Permission|Collection $permissions * * @return Permission|Permission[]|Collection */ protected function getStoredPermission($permissions) { if (is_numeric($permissions)) { return app(Permission::class)->findById($permissions); } if (is_string($permissions)) { return app(Permission::class)->findByName($permissions); } if (is_array($permissions)) { return app(Permission::class)->whereIn('name', $permissions)->get(); } return $permissions; } /** * Forget the cached permissions. */ public function forgetCachedPermissions() { app(PermissionService::class)->forgetCachedPermissions(); } }