Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Roles Laravel Package

geniusts/roles

A Laravel package for managing roles and permissions with a simple API. Assign roles to users, define permissions, and control access across your application using lightweight, flexible tools that integrate cleanly with Laravel's authorization system.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and scaffold — pull the package in and publish its assets:

    composer require geniusts/roles
    php artisan vendor:publish --provider="GeniusTS\Roles\RolesServiceProvider"
    php artisan migrate
    

    Publishing gives you the roles, permissions, role_user, and permission_role tables plus a config/roles.php you should skim before migrating in production (table names, model bindings, middleware behavior).

  2. Wire the trait into User — this is the only required code change:

    use GeniusTS\Roles\Traits\HasRoleAndPermission;
    
    class User extends Authenticatable
    {
        use HasRoleAndPermission;
    }
    
  3. Seed your baseline — the package is seed-driven, not UI-driven. Create roles with a slug (the stable identifier you'll reference in code) and a level (used for hierarchy), then attach permissions:

    $admin = Role::create(['name' => 'Admin', 'slug' => 'admin', 'level' => 10]);
    $admin->attachPermission('edit.posts');
    $admin->attachPermission('delete.posts');
    
    $member = Role::create(['name' => 'Member', 'slug' => 'member', 'level' => 1]);
    
  4. First use case: gate a route, render a button. Check the role in a route group and in Blade:

    Route::group(['middleware' => 'role:admin'], function () {
        Route::get('/admin', 'AdminController@index');
    });
    
    @role('admin')
        <a href="/admin">Admin</a>
    @endrole
    

    The middleware aliases role and permission are registered by the service provider, so no manual kernel edits are needed on 6.x/7.x.

Where to look first: the published config (defaults and model overrides), then GeniusTS\Roles\Traits\HasRoleAndPermission — that trait is the whole API surface and reading it will save you hours of guessing.

Implementation Patterns

Role assignment at registration. Attach the default role in your Registered listener or create() flow so no user is ever role-less:

$user = User::create([...]);
$user->attachRole('member'); // slug or Role instance

Hierarchy via level. This is what distinguishes geniusts/roles from flat permission packages. A higher-level user is treated as holding the permissions of lower levels, so $user->level() and $user->can(...) can be used together without explicitly granting every permission up the chain:

if ($user->level() >= 10) { /* admin-only */ }

Permission checks in policies and gates. Because the trait plugs into Gate, prefer $user->can('edit.posts') over checking role slugs in controllers. Reserve hasRole/isRole for coarse UI branching and route grouping; use permissions for anything that could change as the app grows.

Admin management screens. A CRUD page for roles is the standard workflow:

$role->attachPermission($request->permissions);   // array of slugs/IDs
$role->detachPermission('delete.posts');
$user->syncRoles($request->roles);                // if you need full replace

Wrap role mutations in a transaction — the pivots are written separately and a partial failure leaves dangling relationships if the parent role save fails.

Middleware layering. Register both aliases in route groups and stack them when needed:

Route::middleware(['auth', 'role:admin', 'permission:edit.posts'])->group(...);

Blade composition. Use @role / @permission for single checks and fall back to @can for OR-logic:

@permission('edit.posts')
    @include('posts._edit-button')
@endpermission

Testing. Use attachRole in factories/setups and assert with $this->actingAs($user)->get(...)->assertStatus(200). This is faster and more readable than mocking the trait; the package works fine against an in-memory SQLite database as long as you run the package migrations in RefreshDatabase.

Gotchas and Tips

  • Cache is the #1 source of "it works in tinker but not in the browser." Roles/permissions are cached per user. If you change roles in a console command or seeder and the current request still shows the old state, flush the cache (the package exposes a cache key/reset path — check the config and trait; a php artisan cache:clear is the blunt fallback). Do this in deploy scripts after seeding.
  • Level inheritance is directional. Higher level inherits downward, not the reverse. A level => 0 role can't see anything a level => 1 role sees. Set levels deliberately during seeding — changing them later silently changes who can do what.
  • Slug collisions. name is for display, slug is for lookup. Enforce uniqueness on slug in your seeds (firstOrCreate) so re-running db:seed doesn't create duplicates; the pivots will otherwise multiply.
  • Seeding order matters. Create permissions before roles, and roles before users, or attachPermission/attachRole will throw. Guard seeds with firstOrCreate and syncWithoutDetaching-style checks where available.
  • Eager-load roles. $user->hasRole(...) and $user->can(...) trigger relationship queries. On a list of 50 users this becomes a visible N+1; eager load with ->with('roles', 'permissions') on any collection you iterate.
  • Laravel 6/7 only. The package targets those versions explicitly. Do not drop it into an 8+ project without a fork or replacement — the Gate and auth internals changed enough that the integration will be flaky. Treat this as a legacy-friendly package, not a forward-looking one.
  • Maintenance risk. Last release was late 2023 and the package is effectively feature-frozen against older Laravel. For greenfield work, weigh it against spatie/laravel-permission, which has active support and a larger community; geniusts/roles wins primarily if you want the built-in level hierarchy or an existing codebase already depends on it.
  • Middleware alias conflicts. If you've aliased role/permission elsewhere, the package's registration silently clobbers or is clobbered depending on provider order. Confirm app/Http/Kernel.php $routeMiddleware after install.
  • Deleting roles leaves pivots behind. Unless your migration FK cascade is set, $role->delete() orphans role_user rows. Delete with $role->users()->detach() first, or add cascading FKs in a follow-up migration.
  • Extension point: the Role and Permission models. You can swap them via the config to add columns (e.g., description) or override findBySlug. That's the cleanest place to add audit fields without forking.
  • Blade directives don't escape. @role is a structural check only — don't pass user input into it, since the slug is looked up directly. Validate roles/permissions server-side in controllers/policies regardless of what the view rendered.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core