Skip to content

Enum as $cast on Permission model #2805

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
LashchenkoV opened this issue Feb 6, 2025 · 4 comments
Open

Enum as $cast on Permission model #2805

LashchenkoV opened this issue Feb 6, 2025 · 4 comments

Comments

@LashchenkoV
Copy link

LashchenkoV commented Feb 6, 2025

Description

According to the official documentation, Laravel Permission package should support PHP Enums when used as permission names. However, when using a BackedEnum for name, the package fails with the following error:

There is no permission named .. for guard ...
Despite the permission existing in the database, the package does not recognize it when using an Enum cast.

Version: 6.x (latest)
Environment:
PHP: 8.2+
Laravel: 10.x
Database: MySQL 8.0+
OS: macOS

Steps To Reproduce

  1. Create an Enum for Permissions model:
enum PermissionName: string
{
    case CAN_VIEW_TEXT = 'can_view_text';
}
  1. Use Enum in a Custom Permission Model:
use Spatie\Permission\Models\Permission;

class CustomPermission extends Permission
{
    protected $casts = [
        'name' => PermissionName::class, // Officially supported method
    ];
}
  1. Set custom class in config permissions.php

'permission' => \App\Containers\CustomPermission::class,
4. Assign permission to existing role

$role = Role::findByName('role_name');
$role->givePermissionTo(PermissionName::CAN_VIEW_TEXT->value);
or 
$role->givePermissionTo(PermissionName::CAN_VIEW_TEXT);

Expected Behavior
The package should correctly retrieve the permission from the database.
givePermissionTo() should accept an Enum.
Actual Behavior
The package throws an exception stating that the permission does not exist.

The problem is in PermissionRegistrar file.

    public function getPermissions(array $params = [], bool $onlyOne = false): Collection
    {
        $this->loadPermissions();

        $method = $onlyOne ? 'first' : 'filter';

        $permissions = $this->permissions->$method(static function ($permission) use ($params) {
            foreach ($params as $attr => $value) {

// Here we need to check if($permission->getAttribute($attr) is enum) - call ->value.

                if ($permission->getAttribute($attr) != $value) {
                    return false;
                }
            }

            return true;
        });

        if ($onlyOne) {
            $permissions = new Collection($permissions ? [$permissions] : []);
        }

        return $permissions;
    }

Example Application

No response

Version of spatie/laravel-permission package:

6.13

Version of laravel/framework package:

10.x

PHP version:

8.2

Database engine and version:

No response

OS: Windows/Mac/Linux version:

No response

@drbyte
Copy link
Collaborator

drbyte commented Feb 6, 2025

We should probably start by expanding the test suite to account for using $casts with enums.
That'll make it more clear what dependencies are related to this.

I think "fixing" it will also require an update to the contract signatures, to allow for string|BackedEnum for permission names. That would be a breaking change, so might tag a new major version for merging that. And change min PHP requirement to 8.1+.

@drbyte
Copy link
Collaborator

drbyte commented Feb 6, 2025

In the meantime you can still use enums without using $casts. That will let the existing functionality simply convert the enums to their string values when encountered.

Docs have been updated to add this workaround.

@LashchenkoV
Copy link
Author

LashchenkoV commented Feb 6, 2025

You are indeed correct.
I still use enum, but without $casts in my model.

It would be beneficial to include a fix for this bug in the next update, if feasible.

@drbyte drbyte changed the title Enum support is Not Working as Expected Enum as $cast on Permission model Feb 7, 2025
@drbyte
Copy link
Collaborator

drbyte commented Mar 2, 2025

Notes to self:

Ref #2609
Ref #2616
Ref https://github.com/spatie/laravel-permission/blob/main/docs/basic-usage/enums.md

  • Contracts will have to be changed, so targeting v7 for this due to breaking change.
  • Will also drop PHP 8.0 support in v7, for various reasons including that enums aren't supported until PHP 8.1.
  • For thoroughness will probably convert all BackedEnum references to its parent UnitEnum, although our only implementation is with named strings.
  • Would like to rely on Laravel's internal helper function enum_value(), but it's not available in all older versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants