hans-thomas/horus
Horus streamlines roles and permissions in Laravel with Spatie Laravel Permission integration. Batch-create roles/permissions, generate model permissions from policies, and assign permissions to roles quickly. Works with Laravel 10–12 and is supported by Sphinx.
Installation:
composer require hans-thomas/horus
php artisan vendor:publish --tag horus-config
Verify config/horus.php exists and is configured (default settings are fine for most cases).
First Use Case:
Generate a role-permission structure for a model (e.g., Post) using its policy:
php artisan horus:generate Post
This creates:
post role (e.g., editor, admin).PostPolicy (e.g., edit-post, delete-post).Key Files to Review:
config/horus.php: Global settings (e.g., default role/permission naming).app/Policies/PostPolicy.php: Example policy for permission generation.database/seeds/RolesAndPermissionsSeeder.php: Seed file for initial data (if using).Use the Horus facade to register roles and permissions programmatically:
use HansThomas\Horus\Facades\Horus;
// Register a role with permissions
Horus::role('admin')
->permission('create-post')
->permission('edit-post')
->save();
// Assign a role to a user
$user->assignRole('admin');
Workflow:
RolesAndPermissionsSeeder).Horus::role()->permission()->save() for bulk operations.php artisan db:seed.Horus auto-generates permissions from model policies. Example:
// app/Policies/PostPolicy.php
public function edit(User $user, Post $post) { ... }
public function delete(User $user, Post $post) { ... }
Run:
php artisan horus:generate Post
This creates permissions like:
edit-post (from edit() method).delete-post (from delete() method).Tip: Use @method annotations in policies for clarity:
/**
* @method bool view(User $user, Post $post)
*/
Horus extends spatie/laravel-permission. Leverage existing Spatie methods:
// Check if a user has a permission
if ($user->can('edit-post')) { ... }
// Sync permissions for a role
$role->syncPermissions(['edit-post', 'delete-post']);
Pattern: Use Horus for initial setup and Spatie for runtime checks.
Override default naming conventions in config/horus.php:
'permissions' => [
'name' => 'custom-{method}-{model}', // e.g., "custom-edit-post"
],
Or use closures for dynamic naming:
'permissions' => [
'name' => fn($method, $model) => strtolower("{$model}.{$method}"),
],
Create a seeder to populate roles/permissions:
// database/seeds/RolesAndPermissionsSeeder.php
public function run()
{
Horus::role('editor')
->permission('create-post')
->permission('publish-post')
->save();
Horus::role('admin')
->permission('manage-users')
->permission('edit-post')
->save();
}
Run:
php artisan db:seed --class=RolesAndPermissionsSeeder
Policy Method Naming:
public and follow Laravel’s authorization conventions (e.g., edit(), not canEdit()).Permission Name Collisions:
edit() in PostPolicy and UserPolicy), permissions may clash.Seeder Order:
Caching Issues:
php artisan cache:clear
php artisan horus:generate Post
Verify Generated Permissions:
Check the permissions table after running horus:generate:
SELECT * FROM permissions WHERE name LIKE '%post%';
Log Permission Generation:
Enable Horus logging in config/horus.php:
'logging' => true,
Check storage/logs/laravel.log for generation details.
Check Policy Coverage: Run:
php artisan horus:check Post
This lists all methods in PostPolicy and whether they were converted to permissions.
Custom Permission Logic:
Extend the HorusServiceProvider to add logic before/after permission generation:
// app/Providers/HorusServiceProvider.php
public function boot()
{
Horus::extend(function ($role) {
// Add custom permissions dynamically
$role->permission('custom-permission');
return $role;
});
}
GUI Integration: Pair with Sphinx (mentioned in the README) for a visual role/permission manager:
composer require hans-thomas/sphinx
php artisan sphinx:install
API Rate Limiting:
Use Horus to create a bypass-rate-limit permission for API endpoints:
Horus::role('api-admin')
->permission('bypass-rate-limit')
->save();
Then gate your middleware:
if (!$user->can('bypass-rate-limit')) {
// Apply rate limiting
}
ON CONFLICT).Post, User, Product).How can I help you explore Laravel packages today?