Larallow
Permissions and roles pacakge for Laravel
Install / Use
/learn @edulazaro/LarallowREADME
Larallow for Laravel: A package to handle roles and permissions
<p align="center"> <a href="https://packagist.org/packages/edulazaro/larallow"><img src="https://img.shields.io/packagist/dt/edulazaro/larallow" alt="Total Downloads"></a> <a href="https://packagist.org/packages/edulazaro/larallow"><img src="https://img.shields.io/packagist/v/edulazaro/larallow" alt="Latest Stable Version"></a> </p>Larallow is a flexible Laravel package for managing roles and permissions with advanced features including scoped roles and permissions, polymorphic relations, translation support, and seamless integration with PHP enums for permissions. Zero configuration required.
Why this package when Spatie Permissions exists?
Spatie Permissions is a great package. However it stores permissions in the database by default and does not handle well scopes or permissions for different actors, also requiring to specify the guard for each permission. It's all about your preferences and project requirements.
Features
- Manage roles and permissions for any actor model (User, Client, etc.)
- Support for scoped roles via polymorphic roleable models (e.g., specific projects, teams)
- Support for scoped permissions via polymorphic permissionable models (e.g., specific resources)
- Define permissions with a fluent API in a similar way you define Laravel routes
- Fluent querying and checking with Permissions and Roles helper classes
- Built-in translation support for role names without external packages
- Permission hierarchy (implications)
Installation
Add the package via Composer:
composer require edulazaro/larallow
Publish migrations and run them:
php artisan vendor:publish --tag=larallow
php artisan migrate
Quick Start
1. Add traits to your model
use EduLazaro\Larallow\Concerns\HasPermissions;
use EduLazaro\Larallow\Concerns\HasRoles;
class User extends Authenticatable
{
use HasPermissions, HasRoles;
}
2. Define permissions (in a service provider)
use EduLazaro\Larallow\Permission;
Permission::create([
'edit-post' => 'Edit Post',
'delete-post' => 'Delete Post',
])->for(User::class);
3. Assign and check permissions
// Assign a permission
$user->allow('edit-post');
// Or using the permissions() method
$user->permissions('edit-post')->allow();
// Check if user has permission (direct or via role)
$user->permissions('edit-post')->check();
// Check direct permission only
$user->hasPermission('edit-post');
4. Work with roles
use EduLazaro\Larallow\Models\Role;
// Create a role
$role = Role::create(['handle' => 'editor', 'name' => 'Editor']);
// Add permissions to the role
$role->addPermission('edit-post');
// Assign role to user
$user->assignRole($role);
// Check role
$user->hasRole('editor');
Setup
Actor Traits
Add the HasPermissions and HasRoles traits to your actor models (User, Client, etc.):
use EduLazaro\Larallow\Concerns\HasPermissions;
use EduLazaro\Larallow\Concerns\HasRoles;
class User extends Authenticatable
{
use HasPermissions, HasRoles;
}
You can use only one trait if you don't need both features.
Role Tenant Trait
For models that own roles (e.g., Account, Group, Organization), add the IsRoleTenant trait:
use EduLazaro\Larallow\Concerns\IsRoleTenant;
class Account extends Model
{
use IsRoleTenant;
}
This allows you to retrieve roles belonging to that tenant:
$roles = $account->roles()->get();
Morph Maps (Recommended)
For consistent and secure morph relationships, define all models in your morph map:
use Illuminate\Database\Eloquent\Relations\Relation;
// In AppServiceProvider boot()
Relation::morphMap([
'user' => User::class,
'client' => Client::class,
'office' => Office::class,
]);
This is optional but heavily recommended, especially when dealing with multiple actor types or scopes.
Permissions
Defining Permissions
Register permissions using Permission::create() in a service provider:
use EduLazaro\Larallow\Permission;
// Single permission
Permission::create('edit-post')->label('Edit Post');
// Multiple permissions
Permission::create([
'edit-post' => 'Edit Post',
'delete-post' => 'Delete Post',
'view-post' => 'View Post',
]);
For specific actor types
Use for() to restrict permissions to specific actor models:
Permission::create('edit-post')->for(User::class);
Permission::create('manage-account')->for([User::class, Client::class]);
// Using morph map names
Permission::create('edit-post')->for('user');
For specific scopes
Use on() to restrict permissions to specific scope models (e.g., Office, Group):
Permission::create('manage-office')
->for(User::class)
->on(Office::class);
// Multiple scopes
Permission::create('manage-resources')
->for(User::class)
->on([Office::class, Group::class]);
Grouping permissions
Define multiple permissions with shared configuration:
Permission::create([
'manage-clients' => 'Manage Clients',
'manage-properties' => 'Manage Properties',
'manage-appointments' => 'Manage Appointments',
])->for(User::class)
->on([Office::class, Group::class]);
Permission implications (hierarchy)
Define permission hierarchies where higher-level permissions imply lower-level ones:
Permission::create('manage-posts')
->for(User::class)
->implies('edit-post');
Permission::create('edit-post')->for(User::class);
// Users with 'manage-posts' automatically have 'edit-post'
Using enums
Permission::create(UserPermission::EditPost->value)->label('Edit Post');
Permission::create([
UserPermission::EditPost->value => 'Edit Post',
UserPermission::DeletePost->value => 'Delete Post',
])->for(User::class);
Translating permission labels
Permission::create([
'edit-post' => __('Edit Post'),
]);
Or for easier text management you can use Laratext package:
Permission::create([
'edit-post' => text('edit_post', 'Edit Post'),
]);
Assigning Permissions
Assign permissions directly to actors:
// Single permission
$user->allow('edit-post');
$user->allow(UserPermission::EditPost);
// Multiple permissions
$user->allow(['edit-post', 'delete-post']);
With scope
$office = Office::find(1);
$user->allow('manage-office', $office);
Alternative syntax
$user->permissions('edit-post')->allow();
$user->permissions(['edit-post', 'delete-post'])->allow();
Removing Permissions
$user->deny('edit-post');
// With scope
$user->deny('manage-office', $office);
// Alternative
$user->permissions('edit-post')->deny();
Syncing Permissions
Sync permissions to match a given list (adds missing, removes others):
$user->syncPermissions(['edit-post', 'view-post']);
// With scope
$user->syncPermissions(['manage-office'], $office);
Checking Permissions
Direct permissions only
Check if user has a permission directly assigned (not via roles):
$user->hasPermission('edit-post');
$user->hasPermission('edit-post', $scope);
// Multiple (all required)
$user->hasPermissions(['edit-post', 'delete-post']);
You can also retrieve the list of permissions directly assigned to an actor:
$permissions = $user->permissions; // Collection of ActorPermission models
foreach ($permissions as $permission) {
echo $permission->permission; // string permission name
}
// Query specific permissions
$canEdit = $user->permissions()->where('permission', 'edit-post')->exists();
Combined (direct + role-based)
Check if user has permission either directly or via a role:
// Model method (simplest)
$user->permissions('edit-post')->check();
// With scope
$user->permissions('edit-post')->on($office)->check();
// Helper function
permissions('edit-post')->for($user)->check();
// Permissions class (verbose)
Permissions::query()
->permissions('edit-post')
->for($user)
->check();
Check any vs all
// True if user has ANY of these permissions
$user->permissions(['edit-post', 'delete-post'])->check();
// True only if user has ALL permissions
$user->permissions(['edit-post', 'delete-post'])->checkAll();
// With scope
$user->permissions(['edit-post', 'delete-post'])->on($office)->checkAll();
Blade directives
@permissions('edit-post')
<button>Edit Post</button>
@endpermissions
@allpermissions(['edit-post', 'delete-post'])
<button>Manage Post</button>
@endallpermissions
// With scope
@permissions('edit-post', $scope)
<button>Edit Post</button>
@endpermissions
Roles
Creating Roles
use EduLazaro\Larallow\Models\Role;
$role = Role::create([
'handle' => 'editor',
'name' => 'Editor',
]);
// With tenant and scope restrictions
$role = new Role();
$role->handle = 'office_manager';
$role->name = 'Office Manager';
$role->tenant_type = $tenant->getMorphClass();
$role->tenant_id = $tenant->id;
$role->actor_type = 'user';
$role->scope_type = 'office';
$role->save();
Assigning Roles
$user->assignRole($role);
$user->assignRole($roleId);
// Multiple roles
$user->assignRoles([$role1, $role2, $roleId]);
// With scope
$user->assignRole($role, $office);
$user->assignRoles([$role1, $role2], $office);
With tenant (multi-tenancy)
Roles::query()
->roles($roles)
->for($user)
->on($office)
->tenant($group)
->assign();
Removing Roles
$user->removeRole($role);
$user->removeRole($role, $scope);
Syncing Roles
Sync roles to match a given list:
$user->syncRoles([$role1, $role2]);
$user->syncRoles([1, 2, $roleInstance]);
// With scope (only affects roles for that scope)
$user->syncRoles([$managerRole], $office);
