Search by

alifcoder / permissions

alifcoder

A simple role and permission management package for Laravel.

Package info

github.com/alifcoder/permission

pkg:composer/alifcoder/permissions

Statistics

Installs: 381

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.1.2 2026-10-23 12:18 UTC

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 ADMIN bypass support using Gate::before()
  • HasRolesTrait trait 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/permissions
  • config/permission.php
  • database/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|manager requires 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!