alifcoder / permissions
A simple role and permission management package for Laravel.
Requires
- php: >=8.2
- illuminate/support: ^11.0 || ^12.0 || ^13.0
Requires (Dev)
- larastan/larastan: ^3.13
- laravel/framework: ^v12.14.1
- laravel/pint: ^1.32
- orchestra/testbench: ^10.0
- phpstan/phpstan: ^2.3
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A simple, flexible role and permission management system for Laravel applications โ designed to support
Gate::before, SUPER ADMIN logic, modular apps (nwidart/laravel-modules), and dynamic user model resolution.
โจ Features
- Role and permission management with pivot tables
SUPER ADMINbypass support usingGate::before()HasRolesTraittrait for easy user integration- Every role and permission check is answered from memory โ one query per user, per request
- Automatic cache invalidation on every role/permission change
- Dynamically configurable role and permission models (UUID or auto-increment keys)
- Localization: English, Russian and Uzbek messages, customizable per locale
- Clean service provider with publishable config and migrations
- Works with modular Laravel apps (like
nwidart/laravel-modules)
๐ฆ Requirements
- PHP
>=8.2 - Laravel
^11.0 || ^12.0 || ^13.0
๐ Installation
composer require alifcoder/permissions
Then publish the config, translations, and migrations:
php artisan vendor:publish --tag=permissions php artisan migrate
This will publish:
lang/vendor/permissionsconfig/permission.phpdatabase/migrations/xxxx_xx_xx_xxxxxx_create_permissions_table.php
โ๏ธ Configuration
Inside config/permissions.php:
return [ 'models' => [ 'role' => \Alif\Permissions\Models\Role::class, 'permission' => \Alif\Permissions\Models\Permission::class, ], // cache the roles and permissions of every user 'cacheable' => true, // cache store used by the package (null = default store) 'cache_store' => null, // lifetime in seconds of a cached entry (null = forever) 'cache_ttl' => null, // set to false when your primary keys are auto-incrementing integers 'is_model_uuid' => true, ];
You can override the role and permission models here.
โ ๏ธ Caching requires a cache store that supports tags (
redis,memcached,array). When the store is not taggable the package keeps working, it simply reads from the database.
๐งฌ Traits
In your User model, add the trait:
use Alif\Permissions\Traits\HasRolesTrait; class User extends Authenticatable { use HasRolesTrait; }
๐ Super Admin Access
Add this in your app (e.g., AuthServiceProvider) โ or it's auto-registered by the package:
Gate::before(function ($user) { // $user is null on guest checks return $user !== null && $user->isSuperAdmin() ? true : null; });
This lets SUPER ADMIN users bypass all policy/gate checks, and the role / permission middleware.
๐ง Usage
Assign Roles & Permissions
$admin = Role::create(['name' => 'Admin', 's_code' => 'admin']); $edit = Permission::create(['name' => 'products.update']); // role <-> permissions (these methods keep the cache in sync) $admin->givePermissionTo($edit); // model, id or name $admin->syncPermissions(['products.update', 'products.read']); $admin->revokePermissionTo('products.read'); // user <-> roles (these methods keep the cache in sync) $user->assignRoles('admin'); // add, keeps the existing roles $user->syncRoles([$admin, 'manager']); // replace $user->removeRole($admin->id); // detach
Every method accepts a model, a primary key, a role name, a role s_code, or an array/collection of them.
โ ๏ธ
$user->roles()->attach()/$role->permissions()->attach()bypass the package, so they leave a stale cache behind. Use the methods above, or call$user->forgetPermissionCache()/$role->forgetPermissionCache()yourself afterwards.
Check Roles & Permissions
$user->hasAllRoles('admin'); // true $user->hasAnyRole(['admin', 'manager']); // true $user->hasAllPermissions(['products.update']); // true $user->hasAnyPermission('products.update'); // true $user->isSuperAdmin(); // true or false $user->roles; // roles of the user, with their permissions (cached) $user->permissions; // unique permissions of all roles (cached) $user->permissionNames(); // the same, as a plain array of names
All checks above are resolved in memory: the roles of a user are read once (from the cache when it is enabled, otherwise with a single query) and every following check reuses them.
Cache invalidation
The cache is dropped automatically when:
| Change | What is dropped |
|---|---|
assignRoles(), syncRoles(), removeRole() |
the cache of that user |
| the user is deleted | the cache of that user |
givePermissionTo(), syncPermissions(), revokePermissionTo() |
the cache of the users owning that role |
| a role is updated, deleted, restored or force deleted | the cache of the users owning that role |
| a permission is updated or deleted | the cache of the users owning that permission |
๐ Localization
The package ships with English (en), Russian (ru) and Uzbek (uz) translations. All messages, exceptions and console
output use them, the active one follows the application locale (app.locale), and missing keys fall back to English.
To override or add a language, publish the files and edit them:
php artisan vendor:publish --tag=permissions
They are copied to resources/lang/vendor/permissions/{locale}/permissions.php.
๐งโ๐ป Usage macro
Also you can use Route macro to check permissions and roles:
Route::put('/products/{product}', function () { // Your logic here })->permission('products.update'); Route::put('/admin', function () { // Your logic here })->role('admin'); // or the middleware aliases directly, an optional second argument selects the guard Route::put('/admin', fn() => null)->middleware('role:admin|manager,web');
โ ๏ธ Several roles/permissions are checked with AND:
role:admin|managerrequires both roles.
๐งฉ Folder Structure
src/
โโโ Models/
โ โโโ Concerns/
โ โโโ Role.php
โ โโโ Permission.php
โโโ Traits/
โ โโโ HasRolesTrait.php
โโโ Support/
โ โโโ PermissionCache.php
โโโ Middleware/
โโโ Macros/
โโโ Exceptions/
โโโ Helpers/
โโโ Console/
โโโ PermissionServiceProvider.php
config/
โโโ permissions.php
resources/
โโโ lang/en/permissions.php
database/
โโโ migrations/
๐งน Clear permission caches
Run this command to clear the permission cache:
php artisan permission:cache-clear
๐งน Uninstall (Clean Up)
Run this command before removing the package:
php artisan permission:uninstall
It rolls back the migration, deletes the published files and clears the cache. In production it asks for a
confirmation, use --force to skip it.
๐งช Tests
composer install
composer test
The suite runs against orchestra/testbench with an in-memory SQLite database, and covers both UUID and
auto-incrementing primary keys, the cache invalidation matrix, the middlewares, the console commands and the
translations.
To run the cache tests against a real Redis server (the cache is flushed before every test, use a dedicated Redis database):
PERMISSIONS_TEST_CACHE=redis composer test
Code quality
composer pint # fix the code style (Laravel Pint, config in pint.json) composer pint:check # check the code style without changing files composer phpstan # static analysis (PHPStan level 5 with Larastan, config in phpstan.neon)
๐ License
MIT ยฉ Shukhratjon Yuldashev
๐ Contributing
Pull requests and suggestions are welcome!