Installation:
composer require kodeine/laravel-acl
Run migrations:
php artisan migrate
Publish config (optional):
php artisan vendor:publish --provider="Kodeine\Acl\AclServiceProvider"
First Use Case:
Define Roles & Permissions:
// In a seeder or migration
use Kodeine\Acl\Models\Role;
use Kodeine\Acl\Models\Permission;
$adminRole = Role::create(['name' => 'admin']);
$userRole = Role::create(['name' => 'user']);
$createPostPermission = Permission::create(['name' => 'posts.create']);
$editPostPermission = Permission::create(['name' => 'posts.edit']);
$adminRole->attachPermission($createPostPermission);
$adminRole->attachPermission($editPostPermission);
Assign Roles to Users:
$user = User::find(1);
$user->attachRole($adminRole);
Protect Routes:
Route::get('/admin/dashboard', function () {
return view('admin.dashboard');
})->middleware('can:posts.create'); // Requires 'posts.create' permission
Protect Controller Methods:
use Kodeine\Acl\Middleware\AclMiddleware;
class PostController extends Controller
{
public function __construct()
{
$this->middleware('can:posts.create')->only(['store']);
$this->middleware('can:posts.edit')->only(['edit', 'update']);
}
}
Quick Check: Use Tinker to verify permissions:
php artisan tinker
$user = User::find(1);
$user->can('posts.create'); // Returns boolean
Role-Permission Assignment:
$role = Role::find(1);
$permissions = Permission::whereIn('name', ['posts.create', 'posts.edit'])->get();
$role->attachPermissions($permissions);
$role->detachPermission($editPostPermission);
Dynamic Permission Checks:
Route::get('/admin/posts', function () {
return view('posts.index');
})->middleware('can:posts.index');
use Kodeine\Acl\Policies\AclPolicy;
class PostPolicy extends AclPolicy
{
public function viewAny(User $user)
{
return $user->can('posts.index');
}
}
CRUD Controller Protection:
use Kodeine\Acl\Traits\AclCrudTrait;
class PostController extends Controller
{
use AclCrudTrait;
protected $permissionPrefix = 'posts';
protected $crudPermissions = ['index', 'create', 'store', 'edit', 'update', 'destroy'];
}
index() → posts.index).User-Specific Checks:
@can('posts.create')
<a href="{{ route('posts.create') }}">Create Post</a>
@endcan
if ($user->can('posts.destroy')) {
$post->delete();
}
Role-Based Redirects:
Route::get('/admin', function () {
return view('admin.dashboard');
})->middleware('role:admin');
Seeding Roles/Permissions:
RoleSeeder to predefine roles and permissions:
public function run()
{
$adminRole = Role::create(['name' => 'admin']);
$userRole = Role::create(['name' => 'user']);
Permission::create(['name' => 'posts.*'])->roles()->attach($adminRole);
Permission::create(['name' => 'users.manage'])->roles()->attach($adminRole);
}
Wildcard Permissions:
* for bulk permission assignment:
$adminRole->attachPermission(Permission::create(['name' => 'posts.*']));
posts.* permissions (e.g., posts.create, posts.edit).Custom Permission Logic:
Kodeine\Acl\Contracts\Permission for custom logic:
class CustomPermission implements Permission
{
public function userCan(User $user, $ability)
{
// Custom logic here
return $user->isAdmin();
}
}
API Resource Protection:
can middleware:
Route::apiResource('posts', PostController::class)->middleware('can:posts.*');
Caching Permissions:
config/acl.php:
'cache' => [
'enabled' => true,
'driver' => 'file', // or 'redis', 'database'
],
Permission Caching Issues:
php artisan cache:clear
Or manually clear the ACL cache:
\Kodeine\Acl\Facades\Acl::clearCache();
Wildcard Permission Conflicts:
posts.* might override more specific permissions (e.g., posts.create).Middleware Order Matters:
can middleware must run after auth middleware.app/Http/Kernel.php:
protected $middleware = [
// ...
\Illuminate\Auth\Middleware\Authenticate::class,
\Kodeine\Acl\Middleware\AclMiddleware::class,
];
Mass Assignment Risks:
syncPermissions/syncRoles instead of attach to avoid duplicates:
$role->syncPermissions([$permission1, $permission2]);
Database Schema Changes:
acl_roles, acl_permissions, or pivot tables are manually altered.php artisan migrate after updating the package.Permission Check Logging:
config/acl.php:
'debug' => true,
storage/logs/laravel.log.Common Errors:
Class 'Kodeine\Acl\Models\Role' not found:
config/app.php.Call to undefined method:
Route::middleware() vs. Route::group(['middleware' => ...]).Permission Hierarchy Issues:
Acl::getUserPermissions($user) to inspect a user’s permissions:
$permissions = \Kodeine\Acl\Facades\Acl::getUserPermissions(auth()->user());
dd($permissions);
Custom Permission Providers:
Kodeine\Acl\Contracts\PermissionProvider to fetch permissions from external sources (e.g., API):
class ApiPermissionProvider implements PermissionProvider
{
public function getPermissions()
{
return Cache::remember('api-permissions', 60, function () {
return Http::get('https://api.example.com/permissions')->json();
});
}
}
config/acl.php:
'permission_provider' => \App\Providers\ApiPermissionProvider::class,
Event Listeners:
// In EventServiceProvider
protected $listen = [
'Kodeine\Acl\Events\PermissionAttached' => [
\App\Listeners\LogPermissionChange::class,
],
How can I help you explore Laravel packages today?