RMI permissions table/structure & has permission trait
This commit is contained in:
parent
79e5c832db
commit
d9bdc10f78
|
|
@ -5,16 +5,15 @@ return [
|
|||
'models' => [
|
||||
'role' => \Blax\Roles\Models\Role::class,
|
||||
'role_member' => \Blax\Roles\Models\RoleMember::class,
|
||||
'role_permission' => \Blax\Roles\Models\RolePermission::class,
|
||||
'permission' => \Blax\Roles\Models\Permission::class,
|
||||
'permission_usage' => \Blax\Roles\Models\PermissionUsage::class,
|
||||
'permission_members' => \Blax\Roles\Models\PermissionMember::class,
|
||||
'permission_member' => \Blax\Roles\Models\PermissionMember::class,
|
||||
],
|
||||
|
||||
'table_names' => [
|
||||
'permissions' => 'permissions',
|
||||
'permission_usage' => 'permission_usages',
|
||||
'permission_members' => 'permission_members',
|
||||
'permission_member' => 'permission_member',
|
||||
'roles' => 'roles',
|
||||
'role_member' => 'role_members',
|
||||
'role_permission' => 'role_permissions',
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ return new class extends Migration
|
|||
});
|
||||
|
||||
// PermissionMember
|
||||
Schema::create(config('roles.table_names.permission_members'), function (Blueprint $table) {
|
||||
Schema::create(config('roles.table_names.permission_member'), function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('permission_id')->constrained('permissions')->onDelete('cascade');
|
||||
$table->morphs('member');
|
||||
|
|
@ -63,16 +63,6 @@ return new class extends Migration
|
|||
$table->timestamp('expires_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
// RolePermission
|
||||
Schema::create(config('roles.table_names.role_permission'), function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('role_id')->constrained('roles')->onDelete('cascade');
|
||||
$table->foreignId('permission_id')->constrained('permissions')->onDelete('cascade');
|
||||
$table->json('context')->nullable();
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -80,11 +70,10 @@ return new class extends Migration
|
|||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists(config('roles.table_names.role_permission'));
|
||||
Schema::dropIfExists(config('roles.table_names.role_members'));
|
||||
Schema::dropIfExists(config('roles.table_names.roles'));
|
||||
Schema::dropIfExists(config('roles.table_names.permission_usage'));
|
||||
Schema::dropIfExists(config('roles.table_names.permission_members'));
|
||||
Schema::dropIfExists(config('roles.table_names.permission_member'));
|
||||
Schema::dropIfExists(config('roles.table_names.permissions'));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,16 +20,22 @@ class Permission extends Model
|
|||
|
||||
public function usages()
|
||||
{
|
||||
return $this->hasMany(PermissionUsage::class);
|
||||
return $this->hasMany(config('roles.table_names.permission_usage'));
|
||||
}
|
||||
|
||||
public function roles()
|
||||
{
|
||||
return $this->belongsToMany(RolePermission::class);
|
||||
return $this->morphToMany(
|
||||
config('roles.table_names.role'),
|
||||
'member',
|
||||
config('roles.table_names.permission_member'),
|
||||
'permission_id',
|
||||
'member_id'
|
||||
)->where('member_type', config('roles.table_names.role'));
|
||||
}
|
||||
|
||||
public function members()
|
||||
{
|
||||
return $this->hasMany(PermissionMember::class);
|
||||
return $this->hasMany(config('roles.table_names.permission_member'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class PermissionMember extends Model
|
|||
{
|
||||
parent::__construct($attributes);
|
||||
|
||||
$this->table = config('roles.table_names.permission_members') ?: parent::getTable();
|
||||
$this->table = config('roles.table_names.permission_member') ?: parent::getTable();
|
||||
}
|
||||
|
||||
public function permission()
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Blax\Roles\Models;
|
||||
|
||||
use Blax\Roles\Traits\WillExpire;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class RolePermission extends Model
|
||||
{
|
||||
use WillExpire;
|
||||
|
||||
protected $fillable = [
|
||||
'role_id',
|
||||
'permission_id',
|
||||
];
|
||||
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
|
||||
$this->table = config('roles.table_names.role_permissions') ?: parent::getTable();
|
||||
}
|
||||
|
||||
public function role()
|
||||
{
|
||||
return $this->belongsTo(Role::class);
|
||||
}
|
||||
|
||||
public function permission()
|
||||
{
|
||||
return $this->belongsTo(Permission::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ class RolesServiceProvider extends \Illuminate\Support\ServiceProvider
|
|||
public function register()
|
||||
{
|
||||
$this->mergeConfigFrom(
|
||||
__DIR__.'/../config/roles.php',
|
||||
__DIR__ . '/../config/roles.php',
|
||||
'roles'
|
||||
);
|
||||
}
|
||||
|
|
@ -43,11 +43,11 @@ class RolesServiceProvider extends \Illuminate\Support\ServiceProvider
|
|||
}
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../config/roles.php' => $this->app->configPath('roles.php'),
|
||||
__DIR__ . '/../config/roles.php' => $this->app->configPath('roles.php'),
|
||||
], 'roles-config');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../database/migrations/create_blax_role_tables.php.stub' => $this->getMigrationFileName('create_blax_role_tables.php'),
|
||||
__DIR__ . '/../database/migrations/create_blax_role_tables.php.stub' => $this->getMigrationFileName('create_blax_role_tables.php'),
|
||||
], 'roles-migrations');
|
||||
}
|
||||
|
||||
|
|
@ -60,19 +60,18 @@ class RolesServiceProvider extends \Illuminate\Support\ServiceProvider
|
|||
|
||||
$filesystem = $this->app->make(\Illuminate\Filesystem\Filesystem::class);
|
||||
|
||||
return \Illuminate\Support\Collection::make([$this->app->databasePath().DIRECTORY_SEPARATOR.'migrations'.DIRECTORY_SEPARATOR])
|
||||
->flatMap(fn ($path) => $filesystem->glob($path.'*_'.$migrationFileName))
|
||||
->push($this->app->databasePath()."/migrations/{$timestamp}_{$migrationFileName}")
|
||||
return \Illuminate\Support\Collection::make([$this->app->databasePath() . DIRECTORY_SEPARATOR . 'migrations' . DIRECTORY_SEPARATOR])
|
||||
->flatMap(fn($path) => $filesystem->glob($path . '*_' . $migrationFileName))
|
||||
->push($this->app->databasePath() . "/migrations/{$timestamp}_{$migrationFileName}")
|
||||
->first();
|
||||
}
|
||||
|
||||
protected function registerModelBindings(): void
|
||||
{
|
||||
$this->app->bind(\Blax\Roles\Models\Role::class, fn ($app) => $app->make($app->config['roles.models.role']));
|
||||
$this->app->bind(\Blax\Roles\Models\RoleMember::class, fn ($app) => $app->make($app->config['roles.models.role_member']));
|
||||
$this->app->bind(\Blax\Roles\Models\RolePermission::class, fn ($app) => $app->make($app->config['roles.models.role_permission']));
|
||||
$this->app->bind(\Blax\Roles\Models\Permission::class, fn ($app) => $app->make($app->config['roles.models.permission']));
|
||||
$this->app->bind(\Blax\Roles\Models\PermissionUsage::class, fn ($app) => $app->make($app->config['roles.models.permission_usage']));
|
||||
$this->app->bind(\Blax\Roles\Models\PermissionMember::class, fn ($app) => $app->make($app->config['roles.models.permission_members']));
|
||||
$this->app->bind(\Blax\Roles\Models\Role::class, fn($app) => $app->make($app->config['roles.models.role']));
|
||||
$this->app->bind(\Blax\Roles\Models\RoleMember::class, fn($app) => $app->make($app->config['roles.models.role_member']));
|
||||
$this->app->bind(\Blax\Roles\Models\Permission::class, fn($app) => $app->make($app->config['roles.models.permission']));
|
||||
$this->app->bind(\Blax\Roles\Models\PermissionUsage::class, fn($app) => $app->make($app->config['roles.models.permission_usage']));
|
||||
$this->app->bind(\Blax\Roles\Models\PermissionMember::class, fn($app) => $app->make($app->config['roles.models.permission_member']));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,26 +2,117 @@
|
|||
|
||||
namespace Blax\Roles\Traits;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
trait HasPermissions
|
||||
{
|
||||
public function hasPermission(string $permission, array $context = []): bool
|
||||
public function hasPermission(string $permission): bool
|
||||
{
|
||||
return $this->permissions()
|
||||
->where('name', $permission)
|
||||
->where(function ($query) use ($context) {
|
||||
if (!empty($context)) {
|
||||
$query->where('context', $context);
|
||||
}
|
||||
})
|
||||
->orWhere('slug', '*')
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function permissions()
|
||||
{
|
||||
return $this->morphToMany(
|
||||
config('roles.models.permission'),
|
||||
$permissionClass = config('roles.models.permission');
|
||||
$permissionTable = config('roles.table_names.permissions');
|
||||
$permissionMemberTable = config('roles.table_names.permission_member');
|
||||
|
||||
// direct assignment
|
||||
$direct = $this->morphToMany(
|
||||
$permissionClass,
|
||||
'member',
|
||||
config('roles.table_names.permission_members')
|
||||
$permissionMemberTable
|
||||
);
|
||||
|
||||
if (! method_exists($this, 'roles')) {
|
||||
return $direct;
|
||||
}
|
||||
|
||||
// inherited via roles
|
||||
$permissionRoleTable = config('roles.table_names.permission_role');
|
||||
$roleMemberTable = config('roles.table_names.role_member');
|
||||
$memberType = $this->getMorphClass();
|
||||
|
||||
$viaRoles = $permissionClass::query()
|
||||
->select("$permissionTable.*")
|
||||
->join($permissionRoleTable, "$permissionTable.id", '=', "$permissionRoleTable.permission_id")
|
||||
->join($roleMemberTable, "$permissionRoleTable.role_id", '=', "$roleMemberTable.role_id")
|
||||
->where("$roleMemberTable.member_id", $this->getKey())
|
||||
->where("$roleMemberTable.member_type", $memberType);
|
||||
|
||||
return $direct->union($viaRoles);
|
||||
}
|
||||
|
||||
public function addPermission($permission): bool
|
||||
{
|
||||
$permission_class = config('roles.models.permission');
|
||||
|
||||
if (is_numeric($permission)) {
|
||||
$permission = $permission_class::find($permission);
|
||||
} elseif (is_string($permission)) {
|
||||
$permission = $permission_class::where('slug', $permission)->firstOrCreate();
|
||||
} elseif ($permission instanceof $permission_class) {
|
||||
// Already a Permission instance
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Permission must be a string, numeric ID, or an instance of Permission.');
|
||||
}
|
||||
|
||||
if ($permission) {
|
||||
return $this->permissions()->attach($permission);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function removePermission($permission): bool
|
||||
{
|
||||
$permission_class = config('roles.models.permission');
|
||||
|
||||
if (is_numeric($permission)) {
|
||||
$permission = $permission_class::find($permission);
|
||||
} elseif (is_string($permission)) {
|
||||
$permission = $permission_class::where('slug', $permission)->first();
|
||||
} elseif ($permission instanceof $permission_class) {
|
||||
// Already a Permission instance
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Permission must be a string, numeric ID, or an instance of Permission.');
|
||||
}
|
||||
|
||||
if ($permission) {
|
||||
return $this->permissions()->detach($permission);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all permissions directly assigned or inherited via roles.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function allPermissions(): Collection
|
||||
{
|
||||
// Directly assigned permissions
|
||||
$direct = $this->permissions()->get();
|
||||
|
||||
// Permissions via roles (if the roles() relation exists)
|
||||
if (method_exists($this, 'roles')) {
|
||||
$rolePermissions = $this->roles()
|
||||
->with('permissions')
|
||||
->get()
|
||||
->pluck('permissions')
|
||||
->flatten();
|
||||
} else {
|
||||
$rolePermissions = collect();
|
||||
}
|
||||
|
||||
// Merge and dedupe by 'id'
|
||||
return $direct
|
||||
->merge($rolePermissions)
|
||||
->unique('id')
|
||||
->values();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue