Roles & permissions
Permissions::role() and Permissions::permission() are idempotent under the unique name index, and they create and return the model you configured at permissions.models.* — so a host subclass gets its own class back, its own model events and its own observers. Role::findOrCreate() and Permission::findOrCreate() are sugar for the same calls:
use RoundlyConsulting\Permissions\Facades\Permissions;
$role = Permissions::role('administrator');
$permission = Permissions::permission('auth.users.view');
// The same thing, from the models:
Role::findOrCreate('administrator');
Permission::findOrCreate('auth.users.view');Both accept a string or a backed enum — the enum’s value becomes the name. Creation uses createOrFirst, so concurrent calls never produce a duplicate.
Looking them up
findRole(), findPermission() and roles() are live queries; permissions() and exists() answer from the cached catalog:
Permissions::findRole('administrator'); // ?Role
Permissions::findPermission('auth.users.view'); // ?Permission — the full row
Permissions::roles(); // every role, ordered by name
Permissions::permissions(); // the cached catalog: id + name only
Permissions::exists('auth.users.view'); // bool, from the cache
Permissions::roleModel()::query()->where(...); // a query on your configured modelSeeding
Because role() and permission() are idempotent and givePermissionTo is additive, the same seeder can run on every deploy without duplicating rows or stripping grants. To register a whole enum in one call, see Backed enums:
use Illuminate\Database\Seeder;
use RoundlyConsulting\Permissions\Facades\Permissions;
final class PermissionSeeder extends Seeder
{
public function run(): void
{
foreach (['auth.users.view', 'auth.users.edit', 'auth.users.delete'] as $name) {
Permissions::permission($name);
}
Permissions::for(Permissions::role('editor'))
->givePermissionTo('auth.users.view', 'auth.users.edit');
Permissions::for(Permissions::role('administrator'))
->givePermissionTo('auth.users.view', 'auth.users.edit', 'auth.users.delete');
}
}Reading roles and permissions
$role->permissions; // Collection<Permission> granted to the role
$role->getPermissionNames(); // Collection<string>
$role->hasPermissionTo('auth.users.view'); // bool — the role's own grants
$permission->roles; // Collection<Role> that carry the permissionDescriptions
Both models carry an optional translatable description — a per-locale label for admin screens. See Translatable descriptions for reading and fallback rules:
$role->update(['description' => ['en' => 'Administrator', 'sk' => 'Administrátor']]);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.