Car-Repairs-Shop/app/Traits/HasRolesAndPermissions.php
sackey e839d40a99
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
Initial commit
2025-07-30 17:15:50 +00:00

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();
}
}