The Permissions facade
Everything goes through the Permissions facade (auto-aliased as Permissions). Its root is RoundlyConsulting\Permissions\PermissionsManager, a singleton you can also inject. Every name-taking method accepts a string or a BackedEnum:
use RoundlyConsulting\Permissions\Facades\Permissions;
// Catalog
Permissions::role('editor'); // find or create — Role
Permissions::permission('posts.edit'); // find or create — Permission
Permissions::findRole('editor'); // ?Role
Permissions::findPermission('posts.edit'); // ?Permission — the full row
Permissions::roles(); // Collection<Role>, ordered by name
Permissions::permissions(); // the cached catalog: id + name
Permissions::exists('posts.edit'); // bool, from the cache
Permissions::syncFrom(PostPermission::class); // SyncResult
Permissions::syncRolesFrom(RoleName::class); // SyncResult
// Grants for one holder — every verb returns the holder
Permissions::for($user)->assignRole('editor');
Permissions::for($user)->removeRole('editor');
Permissions::for($user)->syncRoles(['editor']);
Permissions::for($user)->givePermissionTo('posts.edit');
Permissions::for($user)->revokePermissionTo('posts.edit');
Permissions::for($user)->syncPermissions([PostPermission::Edit]);
Permissions::for($user)->forgetAllAuthorization();
// Housekeeping and configuration
Permissions::cache()->forget();
Permissions::cache()->flushMemo();
Permissions::pruneOrphans(); // int — rows deleted
Permissions::roleModel(); // class-string<Role>
Permissions::permissionModel(); // class-string<Permission>
// Tests
$fake = Permissions::fake(); // PermissionsFakeMethods
| Method | Returns | Purpose |
|---|---|---|
role($name) | Role | Find or create a role, as your configured model. |
permission($name) | Permission | Find or create a permission, as your configured model. |
findRole($name) | ?Role | Look a role up by name; null when missing. A live query. |
findPermission($name) | ?Permission | Look a permission up by name — the full row, description included. |
roles() | Collection<Role> | Every role, ordered by name. A live query. |
permissions() | Collection<Permission> | The cached permission catalog — id and name only. |
exists($name) | bool | Whether a permission is registered, answered from the cache. |
syncFrom(Enum::class) | SyncResult | Register one permission per case of a backed enum. Additive. |
syncRolesFrom(Enum::class) | SyncResult | Register one role per case of a backed enum. Additive. |
for($holder) | HolderGrants | Role and permission writes scoped to one holder. |
cache() | PermissionCache | forget() drops the cached catalog; flushMemo() drops only this process’s memo. |
pruneOrphans() | int | Delete grant rows whose holder no longer exists; returns the count. |
roleModel() / permissionModel() | class-string | Your configured model classes. |
fake() | PermissionsFake | Swap in the recording fake — facade only. |
Writes for one holder: for()
Permissions::for($holder) returns a HolderGrants handle with the same write verbs as the traits. Every verb returns the holder:
use RoundlyConsulting\Permissions\Facades\Permissions;
Permissions::for($user)->assignRole('editor');
Permissions::for($user)->syncPermissions([PostPermission::Edit]);
$role = Permissions::role('editor');
Permissions::for($role)->givePermissionTo('posts.edit'); // a Role holds permissions
// The trait methods are sugar over the same handle:
$user->assignRole('editor'); // === Permissions::for($user)->assignRole('editor')| Permissions::for($holder)->… | Does | Holder must |
|---|---|---|
assignRole(...$roles) | Additively assign roles. | use HasRoles |
removeRole(...$roles) | Detach roles. | use HasRoles |
syncRoles($roles) | Make the given roles the exact set. | use HasRoles |
givePermissionTo(...$permissions) | Additively grant direct permissions. | use HasPermissions — a Role or any HasRoles model |
revokePermissionTo(...$permissions) | Detach direct permissions. | use HasPermissions |
syncPermissions($permissions) | Make the given direct permissions the exact set. | use HasPermissions |
forgetAllAuthorization() | Detach every role and direct permission. | use HasRoles |
The scope is a boundary. Role writes refuse a model without HasRoles — including a Role, which holds permissions, never roles. Permission writes refuse a model without HasPermissions, and both refuse a holder that has no key yet. Each refusal is a PermissionException, thrown before anything is written; unknown names throw RoleDoesNotExist or PermissionDoesNotExist.
Where each part is documented
- role(), permission(), findRole(), findPermission(), roles() — Roles & permissions.
- syncFrom(), syncRolesFrom() — Backed enums.
- for()->… role verbs — Assigning roles; permission verbs — Granting permissions.
- permissions(), exists(), cache() — Caching.
- pruneOrphans() — Deleting holders.
- fake() — Testing.
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 cryptoBy 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.