laravel-permission
laravel-permission copied to clipboard
Enums shouldn't be casted in the model
Describe the bug
I am using an enum for my roles. It is called UserRoleEnum
. I somehow thought that I need to cast the enum when saving in the database. So I added the following to my Role
-Model
protected $casts = [
'name' => UserRoleEnum::class,
];
I know now that this was not needed/causes the package to not work correctly anymore.
Versions
- spatie/laravel-permission package version: 6.3.0
- laravel/framework package: v10.43.0
PHP version: 8.3.1
Database version: MySQL 8.2.0
To Reproduce Steps to reproduce the behavior:
- Setup Laravel and the permission package
- Use an enum for the Role
- Cast the enum in the Model
- Assign a user any role
- Use
hasRole(UserRoleEnum::<ROLE>)
and it will always return false
Here is my example code and/or tests showing the problem in my app:
The first output are the user roles, the second one the name of the first role and the third one the
hasRole
-check
Example Application I didn't create one so far. If you prefer to have one I can set one up.
Expected behavior I am not sure if it is a bug or a missing information in the documentation (I know that it should say not to cast but it would have saved me a few hours). Both would be valid fixes for me.
Environment (please complete the following information, because it helps us investigate better):
- OS: macOS
- Version 14.2.1
Instead of $users[0]->hasRole(UserRoleEnum::ADMIN->value)
, does it work if you remove the -value
part? (because it does that internally)
Instead of
$users[0]->hasRole(UserRoleEnum::ADMIN->value)
, does it work if you remove the-value
part? (because it does that internally)
Thanks for your quick response. Unfortunately both options do not work. I am ending up in the HasRole.php::242
-Trait. Where the code is
if (is_string($roles)) {
return $guard
? $this->roles->where('guard_name', $guard)->contains('name', $roles)
: $this->roles->contains('name', $roles);
}
and my values are
$roles = "admin";
$guard = null;
$this->roles
is an array with the correct role model. So I didn't understand in the beginning why it didn't work. But my guess is that the contains checks the string
value and probably compares it to the enum which it gets when casting it.
Hi,
did a fix for this. It's more like a new feature than a bug 🙂
Would this also work to cast permissions to an enum?
@lucacastelnuovo I didn't code such a feature directly but you can give a try. Comment here if it doesn't work with link to a new feature request. I will manage to code it.
@gajosadrian thank you for your prompt response. I will try to take look this weekend. I'm not very familiar with package development so I'll see where I land.
From what I could see I think this will just work. Have to look further. https://github.com/spatie/laravel-permission/blob/da5c8bc931692fa0a1a0fbda1a5995c9379e4159/tests/HasPermissionsTest.php#L73
@lucacastelnuovo this probably refers to the situation where permissions are not cast to enums and we want to use an enum with the same string key as the permissions key. There was a casting issue in this thread because the roles were mapped from string to enum.
protected $casts = [
'name' => UserRoleEnum::class,
];
So probably permissions won't work the same way.