Skip to content

Commit

Permalink
feat(Roles): Support for casting role names to enums (#2616)
Browse files Browse the repository at this point in the history
* feat(Roles): Support for casting role names to enums
  • Loading branch information
gajosadrian authored Apr 19, 2024
1 parent 11c1c60 commit 2c5369e
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 12 deletions.
34 changes: 25 additions & 9 deletions src/Traits/HasRoles.php
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,16 @@ public function hasRole($roles, ?string $guard = null): bool

if ($roles instanceof \BackedEnum) {
$roles = $roles->value;

return $this->roles
->when($guard, fn ($q) => $q->where('guard_name', $guard))
->contains(function ($role) use ($roles) {
if ($role->name instanceof \BackedEnum) {
return $role->name->value == $roles;
}

return $role->name == $roles;
});
}

if (is_int($roles) || PermissionRegistrar::isUid($roles)) {
Expand Down Expand Up @@ -295,9 +305,7 @@ public function hasAllRoles($roles, ?string $guard = null): bool
}

if (is_string($roles)) {
return $guard
? $this->roles->where('guard_name', $guard)->contains('name', $roles)
: $this->roles->contains('name', $roles);
return $this->hasRole($roles, $guard);
}

if ($roles instanceof Role) {
Expand All @@ -312,17 +320,25 @@ public function hasAllRoles($roles, ?string $guard = null): bool
return $role instanceof Role ? $role->name : $role;
});

return $roles->intersect(
$guard
? $this->roles->where('guard_name', $guard)->pluck('name')
: $this->getRoleNames()
) == $roles;
$roleNames = $guard
? $this->roles->where('guard_name', $guard)->pluck('name')
: $this->getRoleNames();

$roleNames = $roleNames->transform(function ($roleName) {
if ($roleName instanceof \BackedEnum) {
return $roleName->value;
}

return $roleName;
});

return $roles->intersect($roleNames) == $roles;
}

/**
* Determine if the model has exactly all of the given role(s).
*
* @param string|array|Role|Collection $roles
* @param string|array|Role|Collection|\BackedEnum $roles
*/
public function hasExactRoles($roles, ?string $guard = null): bool
{
Expand Down
26 changes: 23 additions & 3 deletions tests/HasRolesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,43 @@ public function it_can_assign_and_remove_a_role_using_enums()
{
$enum1 = TestModels\TestRolePermissionsEnum::USERMANAGER;
$enum2 = TestModels\TestRolePermissionsEnum::WRITER;
$enum3 = TestModels\TestRolePermissionsEnum::CASTED_ENUM_1;
$enum4 = TestModels\TestRolePermissionsEnum::CASTED_ENUM_2;

app(Role::class)->findOrCreate($enum1->value, 'web');
app(Role::class)->findOrCreate($enum2->value, 'web');
app(Role::class)->findOrCreate($enum3->value, 'web');
app(Role::class)->findOrCreate($enum4->value, 'web');

$this->assertFalse($this->testUser->hasRole($enum1));
$this->assertFalse($this->testUser->hasRole($enum2));
$this->assertFalse($this->testUser->hasRole($enum3));
$this->assertFalse($this->testUser->hasRole($enum4));
$this->assertFalse($this->testUser->hasRole('user-manager'));
$this->assertFalse($this->testUser->hasRole('writer'));
$this->assertFalse($this->testUser->hasRole('casted_enum-1'));
$this->assertFalse($this->testUser->hasRole('casted_enum-2'));

$this->testUser->assignRole($enum1);
$this->testUser->assignRole($enum2);
$this->testUser->assignRole($enum3);
$this->testUser->assignRole($enum4);

$this->assertTrue($this->testUser->hasRole($enum1));
$this->assertTrue($this->testUser->hasRole($enum2));
$this->assertTrue($this->testUser->hasRole($enum3));
$this->assertTrue($this->testUser->hasRole($enum4));

$this->assertTrue($this->testUser->hasAllRoles([$enum1, $enum2]));
$this->assertFalse($this->testUser->hasAllRoles([$enum1, $enum2, 'not exist']));
$this->assertTrue($this->testUser->hasRole([$enum1, 'writer']));
$this->assertTrue($this->testUser->hasRole([$enum3, 'casted_enum-2']));

$this->assertTrue($this->testUser->hasExactRoles([$enum2, $enum1]));
$this->assertTrue($this->testUser->hasAllRoles([$enum1, $enum2, $enum3, $enum4]));
$this->assertTrue($this->testUser->hasAllRoles(['user-manager', 'writer', 'casted_enum-1', 'casted_enum-2']));
$this->assertFalse($this->testUser->hasAllRoles([$enum1, $enum2, $enum3, $enum4, 'not exist']));
$this->assertFalse($this->testUser->hasAllRoles(['user-manager', 'writer', 'casted_enum-1', 'casted_enum-2', 'not exist']));

$this->assertTrue($this->testUser->hasExactRoles([$enum4, $enum3, $enum2, $enum1]));
$this->assertTrue($this->testUser->hasExactRoles(['user-manager', 'writer', 'casted_enum-1', 'casted_enum-2']));

$this->testUser->removeRole($enum1);

Expand Down
14 changes: 14 additions & 0 deletions tests/TestModels/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ class Role extends \Spatie\Permission\Models\Role

const HIERARCHY_TABLE = 'roles_hierarchy';

/**
* @return string|\BackedEnum
*/
public function getNameAttribute()
{
$name = $this->attributes['name'];

if (str_contains($name, 'casted_enum')) {
return TestRolePermissionsEnum::from($name);
}

return $name;
}

/**
* @return BelongsToMany
*/
Expand Down
2 changes: 2 additions & 0 deletions tests/TestModels/TestRolePermissionsEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ enum TestRolePermissionsEnum: string
case EDITOR = 'editor';
case USERMANAGER = 'user-manager';
case ADMIN = 'administrator';
case CASTED_ENUM_1 = 'casted_enum-1';
case CASTED_ENUM_2 = 'casted_enum-2';

case VIEWARTICLES = 'view articles';
case EDITARTICLES = 'edit articles';
Expand Down

0 comments on commit 2c5369e

Please sign in to comment.