laravel-permission icon indicating copy to clipboard operation
laravel-permission copied to clipboard

Enums shouldn't be casted in the model

Open schnetzi opened this issue 1 year ago • 3 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

schnetzi avatar Feb 09 '24 21:02 schnetzi

Instead of $users[0]->hasRole(UserRoleEnum::ADMIN->value), does it work if you remove the -value part? (because it does that internally)

drbyte avatar Feb 10 '24 01:02 drbyte

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.

schnetzi avatar Feb 10 '24 07:02 schnetzi

Hi,

did a fix for this. It's more like a new feature than a bug 🙂

gajosadrian avatar Feb 17 '24 04:02 gajosadrian

Would this also work to cast permissions to an enum?

lucacastelnuovo avatar Apr 23 '24 16:04 lucacastelnuovo

@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 avatar Apr 23 '24 19:04 gajosadrian

@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.

lucacastelnuovo avatar Apr 24 '24 15:04 lucacastelnuovo

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 avatar Apr 24 '24 16:04 lucacastelnuovo

@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.

gajosadrian avatar Apr 24 '24 16:04 gajosadrian