spatie/laravel-permission

Enums shouldn't be casted in the model

schnetzi opened this issue · 8 comments

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:
image
The first output are the user roles, the second one the name of the first role and the third one the hasRole-check
image

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.