NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

Every name-taking method accepts a string or a BackedEnum, so you can pass your own permission and role enums (persisted as ->value):

use RoundlyConsulting\Enums\Helpers;

enum PermissionName: string
{
    use Helpers;

    case ViewUsers = 'auth.users.view';
    case EditUsers = 'auth.users.edit';
}

Permissions::for($role)->givePermissionTo(PermissionName::ViewUsers);
Permissions::exists(PermissionName::ViewUsers);
$user->hasPermissionTo(PermissionName::ViewUsers);

The Helpers trait from enums-for-laravel is optional — any PHP backed enum works.

Roles and permissions as enums

Permissions::role() and permission(), every grant and role verb, the checks and Permissions::exists() all take enum cases:

use RoundlyConsulting\Permissions\Facades\Permissions;

enum RoleName: string
{
    case Administrator = 'administrator';
    case Editor = 'editor';
}

Permissions::permission(PermissionName::ViewUsers);
Permissions::for(Permissions::role(RoleName::Editor))->givePermissionTo(PermissionName::ViewUsers);

Permissions::for($user)->assignRole(RoleName::Editor);
$user->hasRole(RoleName::Editor);                   // true
$user->hasPermissionTo(PermissionName::ViewUsers);  // true
Permissions::exists(PermissionName::ViewUsers);     // true

In route middleware

Middleware strings take the enum’s value:

Route::get('/users', UsersController::class)
    ->middleware('can:'.PermissionName::ViewUsers->value);

Seeding from an enum

Keep the enum as the single source of truth and register every case in one call — from a seeder, a deploy step or a service provider. syncFrom() registers permissions, syncRolesFrom() roles, and both return a SyncResult:

use RoundlyConsulting\Permissions\Facades\Permissions;

$result = Permissions::syncFrom(PermissionName::class);
$result->created;   // ['auth.users.edit'] — names registered now
$result->existing;  // ['auth.users.view'] — names that were already there
$result->changed(); // true

Permissions::syncRolesFrom(RoleName::class); // the same, for roles

The sync is additive: it never deletes or renames a row the enum does not name, because other services may register their own permissions in the same tables. Rows are created through your configured models, so the cache invalidates itself. Anything that is not a backed enum throws a PermissionException.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.