297 lines
8.1 KiB
PHP
297 lines
8.1 KiB
PHP
<?php
|
|
|
|
namespace App\Models\Permission\Traits;
|
|
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
use App\Models\Permission\Permission;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Contracts\Auth\Access\Gate;
|
|
use App\Domains\Permission\Services\PermissionService;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
|
|
trait HasPermissions
|
|
{
|
|
public static function bootHasPermissions()
|
|
{
|
|
static::deleting(function ($model) {
|
|
if (method_exists($model, 'isForceDeleting') && ! $model->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();
|
|
}
|
|
}
|