From 41df4182a4f70974bf7ccfaa9ba4d58bdd79ec08 Mon Sep 17 00:00:00 2001 From: Mark Lontoc Date: Wed, 26 Feb 2025 10:50:11 +0800 Subject: [PATCH 01/10] Allow middleware to handle enum based permission --- src/Middleware/PermissionMiddleware.php | 16 ++++++++++++++-- tests/PermissionMiddlewareTest.php | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Middleware/PermissionMiddleware.php b/src/Middleware/PermissionMiddleware.php index 3e78f1d60..30438e180 100644 --- a/src/Middleware/PermissionMiddleware.php +++ b/src/Middleware/PermissionMiddleware.php @@ -42,13 +42,25 @@ public function handle($request, Closure $next, $permission, $guard = null) /** * Specify the permission and guard for the middleware. * - * @param array|string $permission + * @param array|string|\BackedEnum $permission * @param string|null $guard * @return string */ public static function using($permission, $guard = null) { - $permissionString = is_string($permission) ? $permission : implode('|', $permission); + // Convert Enum to its value if an Enum is passed + if ($permission instanceof \BackedEnum) { + $permission = $permission->value; + } + + // Convert array of permissions (including Enum values) to a string + if (is_array($permission)) { + $permission = array_map(fn ($p) => $p instanceof \BackedEnum ? $p->value : $p, $permission); + $permissionString = implode('|', $permission); + } else { + $permissionString = (string) $permission; + } + $args = is_null($guard) ? $permissionString : "$permissionString,$guard"; return static::class.':'.$args; diff --git a/tests/PermissionMiddlewareTest.php b/tests/PermissionMiddlewareTest.php index 4dc233193..31e8da900 100644 --- a/tests/PermissionMiddlewareTest.php +++ b/tests/PermissionMiddlewareTest.php @@ -434,4 +434,22 @@ public function the_middleware_can_be_created_with_static_using_method() PermissionMiddleware::using(['edit-articles', 'edit-news']) ); } + + /** @test */ + #[Test] + public function the_middleware_can_handle_enum_based_permissions() + { + $this->assertSame( + 'Spatie\Permission\Middleware\PermissionMiddleware:view articles', + PermissionMiddleware::using(TestModels\TestRolePermissionsEnum::VIEWARTICLES) + ); + $this->assertEquals( + 'Spatie\Permission\Middleware\PermissionMiddleware:view articles,my-guard', + PermissionMiddleware::using(TestModels\TestRolePermissionsEnum::VIEWARTICLES, 'my-guard') + ); + $this->assertEquals( + 'Spatie\Permission\Middleware\PermissionMiddleware:view articles|edit articles', + PermissionMiddleware::using([TestModels\TestRolePermissionsEnum::VIEWARTICLES, TestModels\TestRolePermissionsEnum::EDITARTICLES]) + ); + } } From a8d77eb7458f35ae7a7865329c58ca08beb81db4 Mon Sep 17 00:00:00 2001 From: Mark Lontoc Date: Wed, 26 Feb 2025 11:02:03 +0800 Subject: [PATCH 02/10] Allow middleware to handle enum based roles --- src/Middleware/RoleMiddleware.php | 15 +++++++++++++-- tests/RoleMiddlewareTest.php | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Middleware/RoleMiddleware.php b/src/Middleware/RoleMiddleware.php index 010363f6e..b2ce45b7e 100644 --- a/src/Middleware/RoleMiddleware.php +++ b/src/Middleware/RoleMiddleware.php @@ -42,13 +42,24 @@ public function handle($request, Closure $next, $role, $guard = null) /** * Specify the role and guard for the middleware. * - * @param array|string $role + * @param array|string|\BackedEnum $role * @param string|null $guard * @return string */ public static function using($role, $guard = null) { - $roleString = is_string($role) ? $role : implode('|', $role); + // Convert Enum to its value if an Enum is passed + if ($role instanceof \BackedEnum) { + $role = $role->value; + } + + if (is_array($role)) { + $role = array_map(fn ($r) => $r instanceof \BackedEnum ? $r->value : $r, $role); + $roleString = implode('|', $role); + } else { + $roleString = (string) $role; + } + $args = is_null($guard) ? $roleString : "$roleString,$guard"; return static::class.':'.$args; diff --git a/tests/RoleMiddlewareTest.php b/tests/RoleMiddlewareTest.php index 532f2061f..43ee70eb3 100644 --- a/tests/RoleMiddlewareTest.php +++ b/tests/RoleMiddlewareTest.php @@ -366,4 +366,22 @@ public function the_middleware_can_be_created_with_static_using_method() RoleMiddleware::using(['testAdminRole', 'anotherRole']) ); } + + /** @test */ + #[Test] + public function the_middleware_can_handle_enum_based_roles() + { + $this->assertSame( + 'Spatie\Permission\Middleware\RoleMiddleware:writer', + RoleMiddleware::using(TestModels\TestRolePermissionsEnum::WRITER) + ); + $this->assertEquals( + 'Spatie\Permission\Middleware\RoleMiddleware:writer,my-guard', + RoleMiddleware::using(TestModels\TestRolePermissionsEnum::WRITER, 'my-guard') + ); + $this->assertEquals( + 'Spatie\Permission\Middleware\RoleMiddleware:writer|editor', + RoleMiddleware::using([TestModels\TestRolePermissionsEnum::WRITER, TestModels\TestRolePermissionsEnum::EDITOR]) + ); + } } From 819ce0ed982a9a36c16eb26eccc53543d91e1946 Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Wed, 26 Feb 2025 19:02:40 -0500 Subject: [PATCH 03/10] Only test enums on PHP 8.1+ --- tests/RoleMiddlewareTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/RoleMiddlewareTest.php b/tests/RoleMiddlewareTest.php index 43ee70eb3..f4b8282b3 100644 --- a/tests/RoleMiddlewareTest.php +++ b/tests/RoleMiddlewareTest.php @@ -367,7 +367,12 @@ public function the_middleware_can_be_created_with_static_using_method() ); } - /** @test */ + /** + * @test + * + * @requires PHP >= 8.1 + */ + #[RequiresPhp('>= 8.1')] #[Test] public function the_middleware_can_handle_enum_based_roles() { From a5cf4fef00207cb8c343c10df829ba09527b17eb Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Wed, 26 Feb 2025 19:03:07 -0500 Subject: [PATCH 04/10] Only test enums on PHP 8.1+ --- tests/PermissionMiddlewareTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/PermissionMiddlewareTest.php b/tests/PermissionMiddlewareTest.php index 31e8da900..90f126147 100644 --- a/tests/PermissionMiddlewareTest.php +++ b/tests/PermissionMiddlewareTest.php @@ -435,7 +435,12 @@ public function the_middleware_can_be_created_with_static_using_method() ); } - /** @test */ + /** + * @test + * + * @requires PHP >= 8.1 + */ + #[RequiresPhp('>= 8.1')] #[Test] public function the_middleware_can_handle_enum_based_permissions() { From 313a47839a9503b11bf3cbaa0838b7bb99b61e77 Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Wed, 26 Feb 2025 19:15:28 -0500 Subject: [PATCH 05/10] Add test for middleware handle() method --- tests/PermissionMiddlewareTest.php | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/PermissionMiddlewareTest.php b/tests/PermissionMiddlewareTest.php index 90f126147..6a00ca2e5 100644 --- a/tests/PermissionMiddlewareTest.php +++ b/tests/PermissionMiddlewareTest.php @@ -442,7 +442,7 @@ public function the_middleware_can_be_created_with_static_using_method() */ #[RequiresPhp('>= 8.1')] #[Test] - public function the_middleware_can_handle_enum_based_permissions() + public function the_middleware_can_handle_enum_based_permissions_with_static_using_method() { $this->assertSame( 'Spatie\Permission\Middleware\PermissionMiddleware:view articles', @@ -457,4 +457,29 @@ public function the_middleware_can_handle_enum_based_permissions() PermissionMiddleware::using([TestModels\TestRolePermissionsEnum::VIEWARTICLES, TestModels\TestRolePermissionsEnum::EDITARTICLES]) ); } + + /** + * @test + * + * @requires PHP >= 8.1 + */ + #[RequiresPhp('>= 8.1')] + #[Test] + public function the_middleware_can_handle_enum_based_permissions_with_handle_method() + { + Auth::login($this->testUser); + $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::VIEWARTICLES); + + $this->assertEquals( + 200, + $this->runMiddleware($this->permissionMiddleware, TestModels\TestRolePermissionsEnum::VIEWARTICLES) + ); + + $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::EDITARTICLES); + + $this->assertEquals( + 200, + $this->runMiddleware($this->permissionMiddleware, [TestModels\TestRolePermissionsEnum::VIEWARTICLES, TestModels\TestRolePermissionsEnum::EDITARTICLES]) + ); + } } From 859cac9d79c87b0244f4e9b6a778bd10c00388bc Mon Sep 17 00:00:00 2001 From: Mark Lontoc Date: Thu, 27 Feb 2025 18:55:41 +0800 Subject: [PATCH 06/10] Role and Permission middlewares handles enums with handle method --- src/Middleware/PermissionMiddleware.php | 33 +++++++++++++++++-------- src/Middleware/RoleMiddleware.php | 27 +++++++++++++------- tests/PermissionMiddlewareTest.php | 3 +++ 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/Middleware/PermissionMiddleware.php b/src/Middleware/PermissionMiddleware.php index 30438e180..9a157611f 100644 --- a/src/Middleware/PermissionMiddleware.php +++ b/src/Middleware/PermissionMiddleware.php @@ -28,9 +28,7 @@ public function handle($request, Closure $next, $permission, $guard = null) throw UnauthorizedException::missingTraitHasRoles($user); } - $permissions = is_array($permission) - ? $permission - : explode('|', $permission); + $permissions = explode('|', self::parsePermissionsToString($permission)); if (! $user->canAny($permissions)) { throw UnauthorizedException::forPermissions($permissions); @@ -53,16 +51,31 @@ public static function using($permission, $guard = null) $permission = $permission->value; } - // Convert array of permissions (including Enum values) to a string - if (is_array($permission)) { - $permission = array_map(fn ($p) => $p instanceof \BackedEnum ? $p->value : $p, $permission); - $permissionString = implode('|', $permission); - } else { - $permissionString = (string) $permission; - } + $permissionString = self::parsePermissionsToString($permission); $args = is_null($guard) ? $permissionString : "$permissionString,$guard"; return static::class.':'.$args; } + + /** + * Convert array or string of permissions to string representation. + * + * @return string + */ + protected static function parsePermissionsToString(array|string|\BackedEnum $permission) + { + // Convert Enum to its value if an Enum is passed + if ($permission instanceof \BackedEnum) { + $permission = $permission->value; + } + + if (is_array($permission)) { + $permission = array_map(fn ($r) => $r instanceof \BackedEnum ? $r->value : $r, $permission); + + return implode('|', $permission); + } + + return (string) $permission; + } } diff --git a/src/Middleware/RoleMiddleware.php b/src/Middleware/RoleMiddleware.php index b2ce45b7e..edc02ff90 100644 --- a/src/Middleware/RoleMiddleware.php +++ b/src/Middleware/RoleMiddleware.php @@ -28,9 +28,7 @@ public function handle($request, Closure $next, $role, $guard = null) throw UnauthorizedException::missingTraitHasRoles($user); } - $roles = is_array($role) - ? $role - : explode('|', $role); + $roles = explode('|', self::parseRolesToString($role)); if (! $user->hasAnyRole($roles)) { throw UnauthorizedException::forRoles($roles); @@ -47,6 +45,20 @@ public function handle($request, Closure $next, $role, $guard = null) * @return string */ public static function using($role, $guard = null) + { + $roleString = self::parseRolesToString($role); + + $args = is_null($guard) ? $roleString : "$roleString,$guard"; + + return static::class.':'.$args; + } + + /** + * Convert array or string of roles to string representation. + * + * @return string + */ + protected static function parseRolesToString(array|string|\BackedEnum $role) { // Convert Enum to its value if an Enum is passed if ($role instanceof \BackedEnum) { @@ -55,13 +67,10 @@ public static function using($role, $guard = null) if (is_array($role)) { $role = array_map(fn ($r) => $r instanceof \BackedEnum ? $r->value : $r, $role); - $roleString = implode('|', $role); - } else { - $roleString = (string) $role; + + return implode('|', $role); } - - $args = is_null($guard) ? $roleString : "$roleString,$guard"; - return static::class.':'.$args; + return (string) $role; } } diff --git a/tests/PermissionMiddlewareTest.php b/tests/PermissionMiddlewareTest.php index 6a00ca2e5..e373a23b2 100644 --- a/tests/PermissionMiddlewareTest.php +++ b/tests/PermissionMiddlewareTest.php @@ -467,6 +467,9 @@ public function the_middleware_can_handle_enum_based_permissions_with_static_usi #[Test] public function the_middleware_can_handle_enum_based_permissions_with_handle_method() { + app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::VIEWARTICLES]); + app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::EDITARTICLES]); + Auth::login($this->testUser); $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::VIEWARTICLES); From 3d0134b4e09ee67428eb53f6a9574b61f29fee84 Mon Sep 17 00:00:00 2001 From: Mark Lontoc Date: Fri, 28 Feb 2025 19:16:03 +0800 Subject: [PATCH 07/10] Use enum's value in test --- tests/PermissionMiddlewareTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PermissionMiddlewareTest.php b/tests/PermissionMiddlewareTest.php index e373a23b2..ecd88894c 100644 --- a/tests/PermissionMiddlewareTest.php +++ b/tests/PermissionMiddlewareTest.php @@ -467,8 +467,8 @@ public function the_middleware_can_handle_enum_based_permissions_with_static_usi #[Test] public function the_middleware_can_handle_enum_based_permissions_with_handle_method() { - app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::VIEWARTICLES]); - app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::EDITARTICLES]); + app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::VIEWARTICLES->value]); + app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::EDITARTICLES->value]); Auth::login($this->testUser); $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::VIEWARTICLES); From d22c59ae335b0a58199f78896a7966962941bc2c Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Fri, 28 Feb 2025 15:18:26 -0500 Subject: [PATCH 08/10] Add handle() test --- tests/RoleMiddlewareTest.php | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/RoleMiddlewareTest.php b/tests/RoleMiddlewareTest.php index f4b8282b3..7da48e9d0 100644 --- a/tests/RoleMiddlewareTest.php +++ b/tests/RoleMiddlewareTest.php @@ -374,7 +374,7 @@ public function the_middleware_can_be_created_with_static_using_method() */ #[RequiresPhp('>= 8.1')] #[Test] - public function the_middleware_can_handle_enum_based_roles() + public function the_middleware_can_handle_enum_based_roles_with_static_using_method() { $this->assertSame( 'Spatie\Permission\Middleware\RoleMiddleware:writer', @@ -389,4 +389,32 @@ public function the_middleware_can_handle_enum_based_roles() RoleMiddleware::using([TestModels\TestRolePermissionsEnum::WRITER, TestModels\TestRolePermissionsEnum::EDITOR]) ); } + + /** + * @test + * + * @requires PHP >= 8.1 + */ + #[RequiresPhp('>= 8.1')] + #[Test] + public function the_middleware_can_handle_enum_based_roles_with_handle_method() + { + app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::WRITER->value]); + app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::EDITOR->value]); + + Auth::login($this->testUser); + $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::WRITER); + + $this->assertEquals( + 200, + $this->runMiddleware($this->permissionMiddleware, TestModels\TestRolePermissionsEnum::WRITER) + ); + + $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::EDITOR); + + $this->assertEquals( + 200, + $this->runMiddleware($this->permissionMiddleware, [TestModels\TestRolePermissionsEnum::WRITER, TestModels\TestRolePermissionsEnum::EDITOR]) + ); + } } From 7009370f88995535d75f6c65ee607809509b68a2 Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Fri, 28 Feb 2025 15:23:19 -0500 Subject: [PATCH 09/10] Import class --- tests/RoleMiddlewareTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/RoleMiddlewareTest.php b/tests/RoleMiddlewareTest.php index 7da48e9d0..67c1455f4 100644 --- a/tests/RoleMiddlewareTest.php +++ b/tests/RoleMiddlewareTest.php @@ -9,6 +9,7 @@ use InvalidArgumentException; use Laravel\Passport\Passport; use PHPUnit\Framework\Attributes\Test; +use Spatie\Permission\Contracts\Role; use Spatie\Permission\Exceptions\UnauthorizedException; use Spatie\Permission\Middleware\RoleMiddleware; use Spatie\Permission\Tests\TestModels\UserWithoutHasRoles; @@ -399,8 +400,8 @@ public function the_middleware_can_handle_enum_based_roles_with_static_using_met #[Test] public function the_middleware_can_handle_enum_based_roles_with_handle_method() { - app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::WRITER->value]); - app(Permission::class)->create(['name' => TestModels\TestRolePermissionsEnum::EDITOR->value]); + app(Role::class)->create(['name' => TestModels\TestRolePermissionsEnum::WRITER->value]); + app(Role::class)->create(['name' => TestModels\TestRolePermissionsEnum::EDITOR->value]); Auth::login($this->testUser); $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::WRITER); From f8897b4b446ddb493f2efcadcd8f228c954b5571 Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Fri, 28 Feb 2025 15:26:32 -0500 Subject: [PATCH 10/10] Update RoleMiddlewareTest.php --- tests/RoleMiddlewareTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/RoleMiddlewareTest.php b/tests/RoleMiddlewareTest.php index 67c1455f4..6cf01e2dd 100644 --- a/tests/RoleMiddlewareTest.php +++ b/tests/RoleMiddlewareTest.php @@ -404,18 +404,18 @@ public function the_middleware_can_handle_enum_based_roles_with_handle_method() app(Role::class)->create(['name' => TestModels\TestRolePermissionsEnum::EDITOR->value]); Auth::login($this->testUser); - $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::WRITER); + $this->testUser->assignRole(TestModels\TestRolePermissionsEnum::WRITER); $this->assertEquals( 200, - $this->runMiddleware($this->permissionMiddleware, TestModels\TestRolePermissionsEnum::WRITER) + $this->runMiddleware($this->roleMiddleware, TestModels\TestRolePermissionsEnum::WRITER) ); - $this->testUser->givePermissionTo(TestModels\TestRolePermissionsEnum::EDITOR); + $this->testUser->assignRole(TestModels\TestRolePermissionsEnum::EDITOR); $this->assertEquals( 200, - $this->runMiddleware($this->permissionMiddleware, [TestModels\TestRolePermissionsEnum::WRITER, TestModels\TestRolePermissionsEnum::EDITOR]) + $this->runMiddleware($this->roleMiddleware, [TestModels\TestRolePermissionsEnum::WRITER, TestModels\TestRolePermissionsEnum::EDITOR]) ); } }