RMI permissions table/structure & has permission trait
This commit is contained in:
parent
79e5c832db
commit
d9bdc10f78
|
|
@ -5,16 +5,15 @@ return [
|
||||||
'models' => [
|
'models' => [
|
||||||
'role' => \Blax\Roles\Models\Role::class,
|
'role' => \Blax\Roles\Models\Role::class,
|
||||||
'role_member' => \Blax\Roles\Models\RoleMember::class,
|
'role_member' => \Blax\Roles\Models\RoleMember::class,
|
||||||
'role_permission' => \Blax\Roles\Models\RolePermission::class,
|
|
||||||
'permission' => \Blax\Roles\Models\Permission::class,
|
'permission' => \Blax\Roles\Models\Permission::class,
|
||||||
'permission_usage' => \Blax\Roles\Models\PermissionUsage::class,
|
'permission_usage' => \Blax\Roles\Models\PermissionUsage::class,
|
||||||
'permission_members' => \Blax\Roles\Models\PermissionMember::class,
|
'permission_member' => \Blax\Roles\Models\PermissionMember::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'table_names' => [
|
'table_names' => [
|
||||||
'permissions' => 'permissions',
|
'permissions' => 'permissions',
|
||||||
'permission_usage' => 'permission_usages',
|
'permission_usage' => 'permission_usages',
|
||||||
'permission_members' => 'permission_members',
|
'permission_member' => 'permission_member',
|
||||||
'roles' => 'roles',
|
'roles' => 'roles',
|
||||||
'role_member' => 'role_members',
|
'role_member' => 'role_members',
|
||||||
'role_permission' => 'role_permissions',
|
'role_permission' => 'role_permissions',
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ return new class extends Migration
|
||||||
});
|
});
|
||||||
|
|
||||||
// PermissionMember
|
// 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->id();
|
||||||
$table->foreignId('permission_id')->constrained('permissions')->onDelete('cascade');
|
$table->foreignId('permission_id')->constrained('permissions')->onDelete('cascade');
|
||||||
$table->morphs('member');
|
$table->morphs('member');
|
||||||
|
|
@ -63,16 +63,6 @@ return new class extends Migration
|
||||||
$table->timestamp('expires_at')->nullable();
|
$table->timestamp('expires_at')->nullable();
|
||||||
$table->timestamps();
|
$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
|
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.role_members'));
|
||||||
Schema::dropIfExists(config('roles.table_names.roles'));
|
Schema::dropIfExists(config('roles.table_names.roles'));
|
||||||
Schema::dropIfExists(config('roles.table_names.permission_usage'));
|
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'));
|
Schema::dropIfExists(config('roles.table_names.permissions'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,22 @@ class Permission extends Model
|
||||||
|
|
||||||
public function usages()
|
public function usages()
|
||||||
{
|
{
|
||||||
return $this->hasMany(PermissionUsage::class);
|
return $this->hasMany(config('roles.table_names.permission_usage'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function roles()
|
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()
|
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);
|
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()
|
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()
|
public function register()
|
||||||
{
|
{
|
||||||
$this->mergeConfigFrom(
|
$this->mergeConfigFrom(
|
||||||
__DIR__.'/../config/roles.php',
|
__DIR__ . '/../config/roles.php',
|
||||||
'roles'
|
'roles'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -43,15 +43,15 @@ class RolesServiceProvider extends \Illuminate\Support\ServiceProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->publishes([
|
$this->publishes([
|
||||||
__DIR__.'/../config/roles.php' => $this->app->configPath('roles.php'),
|
__DIR__ . '/../config/roles.php' => $this->app->configPath('roles.php'),
|
||||||
], 'roles-config');
|
], 'roles-config');
|
||||||
|
|
||||||
$this->publishes([
|
$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');
|
], 'roles-migrations');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns existing migration file if found, else uses the current timestamp.
|
* Returns existing migration file if found, else uses the current timestamp.
|
||||||
*/
|
*/
|
||||||
protected function getMigrationFileName(string $migrationFileName): string
|
protected function getMigrationFileName(string $migrationFileName): string
|
||||||
|
|
@ -60,19 +60,18 @@ class RolesServiceProvider extends \Illuminate\Support\ServiceProvider
|
||||||
|
|
||||||
$filesystem = $this->app->make(\Illuminate\Filesystem\Filesystem::class);
|
$filesystem = $this->app->make(\Illuminate\Filesystem\Filesystem::class);
|
||||||
|
|
||||||
return \Illuminate\Support\Collection::make([$this->app->databasePath().DIRECTORY_SEPARATOR.'migrations'.DIRECTORY_SEPARATOR])
|
return \Illuminate\Support\Collection::make([$this->app->databasePath() . DIRECTORY_SEPARATOR . 'migrations' . DIRECTORY_SEPARATOR])
|
||||||
->flatMap(fn ($path) => $filesystem->glob($path.'*_'.$migrationFileName))
|
->flatMap(fn($path) => $filesystem->glob($path . '*_' . $migrationFileName))
|
||||||
->push($this->app->databasePath()."/migrations/{$timestamp}_{$migrationFileName}")
|
->push($this->app->databasePath() . "/migrations/{$timestamp}_{$migrationFileName}")
|
||||||
->first();
|
->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function registerModelBindings(): void
|
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\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\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\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\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']));
|
||||||
$this->app->bind(\Blax\Roles\Models\PermissionMember::class, fn ($app) => $app->make($app->config['roles.models.permission_members']));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,117 @@
|
||||||
|
|
||||||
namespace Blax\Roles\Traits;
|
namespace Blax\Roles\Traits;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
trait HasPermissions
|
trait HasPermissions
|
||||||
{
|
{
|
||||||
public function hasPermission(string $permission, array $context = []): bool
|
public function hasPermission(string $permission): bool
|
||||||
{
|
{
|
||||||
return $this->permissions()
|
return $this->permissions()
|
||||||
->where('name', $permission)
|
->where('name', $permission)
|
||||||
->where(function ($query) use ($context) {
|
->orWhere('slug', '*')
|
||||||
if (!empty($context)) {
|
|
||||||
$query->where('context', $context);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->exists();
|
->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function permissions()
|
public function permissions()
|
||||||
{
|
{
|
||||||
return $this->morphToMany(
|
$permissionClass = config('roles.models.permission');
|
||||||
config('roles.models.permission'),
|
$permissionTable = config('roles.table_names.permissions');
|
||||||
|
$permissionMemberTable = config('roles.table_names.permission_member');
|
||||||
|
|
||||||
|
// direct assignment
|
||||||
|
$direct = $this->morphToMany(
|
||||||
|
$permissionClass,
|
||||||
'member',
|
'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