250 lines
7.8 KiB
PHP
250 lines
7.8 KiB
PHP
<?php
|
|
|
|
namespace App\Traits;
|
|
|
|
use App\Models\Role;
|
|
use App\Models\Permission;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
use Illuminate\Support\Collection;
|
|
|
|
trait HasRolesAndPermissions
|
|
{
|
|
/**
|
|
* Get user's roles
|
|
*/
|
|
public function roles(): BelongsToMany
|
|
{
|
|
return $this->belongsToMany(Role::class, 'user_roles')
|
|
->withPivot(['branch_code', 'is_active', 'assigned_at', 'expires_at'])
|
|
->withTimestamps();
|
|
}
|
|
|
|
/**
|
|
* Get user's direct permissions
|
|
*/
|
|
public function permissions(): BelongsToMany
|
|
{
|
|
return $this->belongsToMany(Permission::class, 'user_permissions')
|
|
->withPivot(['granted', 'branch_code', 'assigned_at', 'expires_at'])
|
|
->withTimestamps();
|
|
}
|
|
|
|
/**
|
|
* Check if user has a specific role
|
|
*/
|
|
public function hasRole(string|array $roles, ?string $branchCode = null): bool
|
|
{
|
|
if (is_array($roles)) {
|
|
return collect($roles)->some(fn($role) => $this->hasRole($role, $branchCode));
|
|
}
|
|
|
|
$query = $this->roles()->where('roles.name', $roles);
|
|
|
|
if ($branchCode) {
|
|
$query->where('user_roles.branch_code', $branchCode);
|
|
}
|
|
|
|
return $query->where('user_roles.is_active', true)
|
|
->where(function ($q) {
|
|
$q->whereNull('user_roles.expires_at')
|
|
->orWhere('user_roles.expires_at', '>', now());
|
|
})
|
|
->exists();
|
|
}
|
|
|
|
/**
|
|
* Check if user has any of the given roles
|
|
*/
|
|
public function hasAnyRole(array $roles, ?string $branchCode = null): bool
|
|
{
|
|
return collect($roles)->some(fn($role) => $this->hasRole($role, $branchCode));
|
|
}
|
|
|
|
/**
|
|
* Check if user has all of the given roles
|
|
*/
|
|
public function hasAllRoles(array $roles, ?string $branchCode = null): bool
|
|
{
|
|
return collect($roles)->every(fn($role) => $this->hasRole($role, $branchCode));
|
|
}
|
|
|
|
/**
|
|
* Check if user has a specific permission
|
|
*/
|
|
public function hasPermission(string $permission, ?string $branchCode = null): bool
|
|
{
|
|
// Check direct permissions first
|
|
$directPermission = $this->permissions()
|
|
->where('permissions.name', $permission)
|
|
->when($branchCode, fn($q) => $q->where('user_permissions.branch_code', $branchCode))
|
|
->where('user_permissions.granted', true)
|
|
->where(function ($q) {
|
|
$q->whereNull('user_permissions.expires_at')
|
|
->orWhere('user_permissions.expires_at', '>', now());
|
|
})
|
|
->exists();
|
|
|
|
if ($directPermission) {
|
|
return true;
|
|
}
|
|
|
|
// Check permissions through roles
|
|
$rolePermissions = $this->roles()
|
|
->when($branchCode, fn($q) => $q->where('user_roles.branch_code', $branchCode))
|
|
->where('user_roles.is_active', true)
|
|
->where(function ($q) {
|
|
$q->whereNull('user_roles.expires_at')
|
|
->orWhere('user_roles.expires_at', '>', now());
|
|
})
|
|
->whereHas('permissions', function ($q) use ($permission) {
|
|
$q->where('permissions.name', $permission)->where('permissions.is_active', true);
|
|
})
|
|
->exists();
|
|
|
|
return $rolePermissions;
|
|
}
|
|
|
|
/**
|
|
* Check if user has any of the given permissions
|
|
*/
|
|
public function hasAnyPermission(array $permissions, ?string $branchCode = null): bool
|
|
{
|
|
return collect($permissions)->some(fn($permission) => $this->hasPermission($permission, $branchCode));
|
|
}
|
|
|
|
/**
|
|
* Check if user has all of the given permissions
|
|
*/
|
|
public function hasAllPermissions(array $permissions, ?string $branchCode = null): bool
|
|
{
|
|
return collect($permissions)->every(fn($permission) => $this->hasPermission($permission, $branchCode));
|
|
}
|
|
|
|
/**
|
|
* Assign a role to user
|
|
*/
|
|
public function assignRole(string|Role $role, ?string $branchCode = null, ?\DateTime $expiresAt = null): self
|
|
{
|
|
if (is_string($role)) {
|
|
$role = Role::where('name', $role)->first();
|
|
}
|
|
|
|
if ($role && !$this->hasRole($role->name, $branchCode)) {
|
|
$this->roles()->attach($role->id, [
|
|
'branch_code' => $branchCode,
|
|
'is_active' => true,
|
|
'assigned_at' => now(),
|
|
'expires_at' => $expiresAt,
|
|
]);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Remove a role from user
|
|
*/
|
|
public function removeRole(string|Role $role, ?string $branchCode = null): self
|
|
{
|
|
if (is_string($role)) {
|
|
$role = Role::where('name', $role)->first();
|
|
}
|
|
|
|
if ($role) {
|
|
$query = $this->roles()->where('role_id', $role->id);
|
|
|
|
if ($branchCode) {
|
|
$query->where('user_roles.branch_code', $branchCode);
|
|
}
|
|
|
|
$query->detach();
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Give permission directly to user
|
|
*/
|
|
public function givePermission(string|Permission $permission, ?string $branchCode = null, ?\DateTime $expiresAt = null): self
|
|
{
|
|
if (is_string($permission)) {
|
|
$permission = Permission::where('name', $permission)->first();
|
|
}
|
|
|
|
if ($permission) {
|
|
$this->permissions()->syncWithoutDetaching([
|
|
$permission->id => [
|
|
'granted' => true,
|
|
'branch_code' => $branchCode,
|
|
'assigned_at' => now(),
|
|
'expires_at' => $expiresAt,
|
|
]
|
|
]);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Revoke permission from user
|
|
*/
|
|
public function revokePermission(string|Permission $permission, ?string $branchCode = null): self
|
|
{
|
|
if (is_string($permission)) {
|
|
$permission = Permission::where('name', $permission)->first();
|
|
}
|
|
|
|
if ($permission) {
|
|
$query = $this->permissions()->where('permission_id', $permission->id);
|
|
|
|
if ($branchCode) {
|
|
$query->where('user_permissions.branch_code', $branchCode);
|
|
}
|
|
|
|
$query->detach();
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get all user permissions (from roles and direct)
|
|
*/
|
|
public function getAllPermissions(?string $branchCode = null): Collection
|
|
{
|
|
// Get direct permissions
|
|
$directPermissions = $this->permissions()
|
|
->when($branchCode, fn($q) => $q->where('user_permissions.branch_code', $branchCode))
|
|
->where('user_permissions.granted', true)
|
|
->where(function ($q) {
|
|
$q->whereNull('user_permissions.expires_at')
|
|
->orWhere('user_permissions.expires_at', '>', now());
|
|
})
|
|
->get();
|
|
|
|
// Get permissions through roles
|
|
$rolePermissions = Permission::whereHas('roles.users', function ($q) use ($branchCode) {
|
|
$q->where('user_id', $this->id)
|
|
->when($branchCode, fn($query) => $query->where('user_roles.branch_code', $branchCode))
|
|
->where('user_roles.is_active', true)
|
|
->where(function ($query) {
|
|
$query->whereNull('user_roles.expires_at')
|
|
->orWhere('user_roles.expires_at', '>', now());
|
|
});
|
|
})->where('is_active', true)->get();
|
|
|
|
return $directPermissions->merge($rolePermissions)->unique('id');
|
|
}
|
|
|
|
/**
|
|
* Check if user can access a specific module
|
|
*/
|
|
public function canAccessModule(string $module, ?string $branchCode = null): bool
|
|
{
|
|
return $this->getAllPermissions($branchCode)
|
|
->where('module', $module)
|
|
->isNotEmpty();
|
|
}
|
|
}
|