hdaklue / porter
Ultra-Minimal Laravel Role Management - Your application's trusted doorkeeper
Requires
- php: ^8.1
- illuminate/cache: ^11.0|^12.0
- illuminate/console: ^11.0|^12.0
- illuminate/database: ^11.0|^12.0
- illuminate/filesystem: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.13
- mockery/mockery: ^1.6
- orchestra/testbench: ^10.6
- pestphp/pest: ^2.0|^3.0
- pestphp/pest-plugin-laravel: ^2.0|^3.0
README
Your application's trusted doorkeeper ๐ช
A lightweight, blazing-fast Laravel role-based access control package that treats roles as what they truly are: domain business logic, not database abstractions. Built for developers who value simplicity, performance, and clean architecture.
"Current RBAC were made for CMSs."
Table of Contents
- Why Porter?
- Roadmap & Community Input
- Core Features โข Complete Guide โ
- Suggested Usage โข Complete Guide โ
- Installation
- Advanced Features
- Configuration
- Laravel Integration โข Complete Guide โ
- Migration Strategy
- Performance
- CLI Commands
- Testing
- Requirements
- Contributing
- License
Why Porter?
"Roles are business logic, not database magic."
Porter was born from the frustration of dealing with bloated RBAC packages that turn simple role assignments into complex database gymnastics. As a fresh package entering the Laravel ecosystem, Porter aims to solve real problems that developers face daily. I believe in providing a solution that is both powerful and elegant, convincing the community that there's a better way to handle role management.
The Problem with Existing Solutions
Most RBAC packages are:
- Over-engineered - 30+ classes for simple role assignments
- Database-heavy - Complex joins and foreign key nightmares
- Performance-blind - Slow queries that don't scale
- Generic - One-size-fits-all approaches that fit no one
Porter's Approach
Porter treats roles as first-class business entities with their own focused classes, not generic database records.
Porter vs Database-Heavy Approaches
Common question: "Why not use traditional database-based RBAC?"
Feature | Database-Heavy RBAC | Porter |
---|---|---|
Role Architecture | Database records | Individual PHP classes |
Permission Storage | Database tables | PHP class methods |
Entity Context | Global permissions | Entity-specific roles |
Type Safety | String-based | Full PHP type safety |
Codebase Size | Many classes/tables | Minimal architecture |
IDE Support | Limited | Full autocomplete |
Performance | Multiple DB queries | Single table, memory checks |
Use Database RBAC if: You need complex global permission matrices
Use Porter if: You need entity-specific roles with type safety and simplicity
Porter's Sweet Spot:
- SaaS applications with fixed role structures
- Enterprise applications with well-defined hierarchies
- Microservices with service-specific roles
- High-performance applications where DB queries are a bottleneck
Note: For true multi-tenancy (shared codebase, tenant-specific roles), consider database-based RBAC packages like. Porter's class-based approach is optimized for applications where roles are business logic, not tenant-variable data.
Roadmap & Community Input
As a new package, your feedback directly shapes Porter's future! I am actively seeking community input and suggestions to prioritize features and ensure Porter evolves into the most valuable tool for your Laravel projects.
๐ฏ Potential Features (Vote & Discuss!)
๐ Granular Permissions System
Fine-grained permissions with contextual validation.
Benefits:
- ๐ฏ Ultra-granular control
- ๐ Context-aware validation
- ๐ Dynamic permission evaluation
- ๐ ๏ธ Complex business rules
๐ REST API Endpoints
Ready-to-use API endpoints for role management.
Benefits:
- ๐ฑ Mobile app integration
- ๐ Third-party service connectivity
- โก Frontend SPA support
- ๐ External dashboard integration
๐ณ๏ธ Help Me Decide!
I want to build what YOU need most. Please share your feedback on:
- Which feature would have the biggest impact on your projects?
- What specific use cases do you have in mind?
- Are there other features not listed that would be valuable?
- What's the best way for the community to provide ongoing feedback?
๐ฌ Community Feedback Options:
We welcome your feedback! Please use:
- GitHub Discussions for ongoing feature conversations.
- Project Wiki for collaborative roadmap planning.
- GitHub Issues for bug reports and feature requests.
๐๏ธ Recognition
Contributors who provide valuable feedback will be:
- ๐ Credited in release notes
- ๐ท๏ธ Mentioned as community advisors
- ๐ Early access to beta features
- ๐ฌ Direct input on API design decisions
Core Features
- ๐ฏ Individual Role Classes: Each role is its own focused class extending
BaseRole
- ๐ Ultra-Minimal Architecture: Just 3 core components for role management
- ๐ฅ Blazing Performance: Optimized for speed with minimal database interaction and built-in caching
- ๐ Latest Features: Dynamic role factory, config-driven architecture, and enhanced Roster model
- ๐จ Perfect Laravel Integration: Seamlessly works with Gates, Policies, and Blade
๐ Complete Core Features Guide โ
Learn about individual role classes, ultra-minimal architecture, blazing performance optimizations, latest features, and perfect Laravel integration.
Suggested Usage
Quick Start
use Hdaklue\Porter\Facades\Porter; // Basic role operations Porter::assign($user, $project, 'admin'); $isAdmin = $user->hasRoleOn($project, 'admin'); Porter::changeRoleOn($user, $project, 'editor');
Create Role Classes
# Interactive role creation with guided setup php artisan porter:create # Or use the dynamic role factory $admin = RoleFactory::admin();
Learn about role creation methods, real-world examples (SaaS, E-commerce, Healthcare), advanced patterns, testing strategies, and configuration best practices.
Installation
composer require hdaklue/porter
Flexible installation with automatic setup:
# Basic installation - creates Porter directory with BaseRole only php artisan porter:install # Full installation - includes 6 default role classes with proper hierarchy php artisan porter:install --roles
The install command: โ Publishes configuration file โ Publishes and runs migrations โ Creates Porter directory with configurable namespace โ Optionally creates 6 default role classes (Admin, Manager, Editor, Contributor, Viewer, Guest) โ Provides contextual next-step guidance โ Blocks installation in production environment for safety
Advanced Features
Role Hierarchy & Smart Comparisons
use App\Porter\{Admin, ProjectManager, Developer, Viewer}; $admin = new Admin(); // Level 10 $manager = new ProjectManager(); // Level 7 $developer = new Developer(); // Level 3 $viewer = new Viewer(); // Level 1 // Intelligent role comparisons $admin->isHigherThan($manager); // true $manager->isHigherThan($developer); // true $developer->isLowerThan($admin); // true $admin->equals(new Admin()); // true // Business logic in your controllers public function canManageProject(User $user, Project $project): bool { $userRole = RoleManager::getRoleOn($user, $project); $requiredRole = new ProjectManager(); return $userRole && $userRole->isHigherThanOrEqual($requiredRole); }
Enhanced Roster Model with Scopes
use Hdaklue\Porter\Models\Roster; // Query role assignments with new scopes $userAssignments = Roster::forAssignable(User::class, $user->id)->get(); $projectRoles = Roster::forRoleable(Project::class, $project->id)->get(); $adminAssignments = Roster::withRoleName('admin')->get(); // Timestamps for audit trails $assignment = Roster::create([...]); echo "Assigned on: " . $assignment->created_at; // Human-readable descriptions foreach ($assignments as $assignment) { echo $assignment->description; // Output: "User #123 has role 'admin' on Project #456" }
Custom Role Classes with Business Logic
final class RegionalManager extends BaseRole { public function getName(): string { return 'regional_manager'; } public function getLevel(): int { return 8; } public function getRegions(): array { return ['north', 'south', 'east', 'west']; } public function canAccessRegion(string $region): bool { return in_array($region, $this->getRegions()); } public function getMaxBudgetApproval(): int { return 100000; // $100k approval limit } } // Usage in business logic if ($user->hasRoleOn($company, 'regional_manager')) { $role = Porter::getRoleOn($user, $company); if ($role->canAccessRegion('north') && $budget <= $role->getMaxBudgetApproval()) { // Approve the budget for northern region } }
Configuration
The config/porter.php
file contains all package settings with configurable options:
return [ // ID Strategy - Works with your existing models 'id_strategy' => env('PORTER_ID_STRATEGY', 'ulid'), // Database connection 'database_connection' => env('PORTER_DB_CONNECTION'), // Role Directory & Namespace Configuration 'directory' => env('PORTER_DIRECTORY', app_path('Porter')), 'namespace' => env('PORTER_NAMESPACE', 'App\\Porter'), // Your role classes (auto-populated by porter:install --roles) 'roles' => [ App\Porter\Admin::class, App\Porter\Manager::class, App\Porter\Editor::class, // ... add your custom roles here ], // Security settings 'security' => [ 'assignment_strategy' => env('PORTER_ASSIGNMENT_STRATEGY', 'replace'), // 'replace' or 'add' 'key_storage' => env('PORTER_KEY_STORAGE', 'hashed'), // 'hashed' or 'plain' 'auto_generate_keys' => env('PORTER_AUTO_KEYS', true), ], // Caching 'cache' => [ 'enabled' => env('PORTER_CACHE_ENABLED', true), 'ttl' => env('PORTER_CACHE_TTL', 3600), // 1 hour ], ];
Security Configuration
// .env file PORTER_ASSIGNMENT_STRATEGY=replace # Default: Replaces existing roles PORTER_ASSIGNMENT_STRATEGY=add # Adds new roles alongside existing ones PORTER_KEY_STORAGE=hashed # Secure (default) - SHA256 hashed role keys PORTER_KEY_STORAGE=plain # Debug mode - Plain text role keys PORTER_AUTO_KEYS=true # Auto-generate keys from class names PORTER_AUTO_KEYS=false # Manual key definition required
Laravel Integration
Porter integrates seamlessly with Laravel's authorization system - Gates, Policies, Blade directives, and middleware all work naturally with Porter's entity-specific roles.
// In your Policy public function update(User $user, Project $project) { return $user->hasRoleOn($project, 'admin'); } // In your Controller $this->authorize('update', $project); // In your Blade templates @can('update', $project) <button>Edit Project</button> @endcan
๐ Complete Laravel Integration Guide โ
Learn about Policies, Middleware, Blade directives, Form Requests, API Resources, Event Listeners, and Testing with Porter.
Migration Strategy
"Porter adapts to YOUR existing models - no changes required!"
Zero-Downtime Migration Strategy
Porter works parallel to your existing role system:
// Phase 1: Install Porter (zero risk) composer require hdaklue/porter php artisan porter:install php artisan migrate // Just adds the `roaster` table // Phase 2: Add traits to existing models (optional) class User extends Authenticatable { use HasUlids; // Add this trait for modern ID strategy // All existing code works unchanged! } // Phase 3: Gradually migrate role checks // Old system keeps working: if ($user->hasRole('admin')) { /* existing code */ } // New Porter system runs parallel: if ($user->hasRoleOn($project, 'admin')) { /* Porter */ } // Phase 4: Switch over when ready (no rush!)
Flexible ID Strategy
// config/porter.php 'id_strategy' => 'integer', // For auto-increment IDs (default Laravel) // OR 'id_strategy' => 'ulid', // For modern ULID IDs // OR 'id_strategy' => 'uuid', // For UUID IDs
Performance
Single Table Architecture
Porter uses exactly ONE database table (roaster
) for all role assignments:
-- The ENTIRE role system in one table: CREATE TABLE roaster ( id bigint PRIMARY KEY, assignable_type varchar(255), -- 'App\Models\User' assignable_id varchar(255), -- ULID: '01HBQM5F8G9YZ2XJKPQR4VWXYZ' roleable_type varchar(255), -- 'App\Models\Project' roleable_id varchar(255), -- ULID: '01HBQM6G9HAZB3YLKQRS5WXYZA' role_key varchar(255), -- 'admin' created_at timestamp, updated_at timestamp, -- Prevents duplicate assignments UNIQUE KEY porter_unique (assignable_type, assignable_id, roleable_type, roleable_id, role_key) );
Performance Benefits:
- ๐ Fewer database queries - single table operations
- ๐ Fast role assignments - simple database operations
- ๐พ Minimal codebase - focused architecture with 8 core classes
- ๐ง Efficient memory usage - individual role classes
- โก No foreign key overhead - polymorphic relationships
CLI Commands
Porter provides several Artisan commands for role management:
Installation Commands
# Basic installation (config, migrations, Porter directory) php artisan porter:install # Full installation with default roles php artisan porter:install --roles # Force overwrite existing files php artisan porter:install --roles --force
Role Management Commands
# Interactive role creation with guided setup php artisan porter:create # Create specific role with description php artisan porter:create ProjectManager --description="Manages development projects" # List all available roles php artisan porter:list # Validate Porter setup and configuration php artisan porter:doctor
Command Features
- Interactive Mode: Guided role creation with automatic level calculation
- Smart Level Management: Automatic hierarchy management (lowest, highest, lower, higher)
- Config-Driven: Uses directory and namespace from configuration
- Production Safe: Install command blocks execution in production
- Force Override:
--force
flag for overwriting existing files - Type Safety: All generated roles implement
RoleContract
Testing
Porter features comprehensive testing with 78 tests and 354 assertions covering real-world scenarios and edge cases.
# Run complete test suite vendor/bin/pest # Run with coverage reporting vendor/bin/pest --coverage # Test specific components vendor/bin/pest tests/Feature/RoleValidatorTest.php # Performance & caching vendor/bin/pest tests/Feature/RoleManagerDatabaseTest.php # Database operations vendor/bin/pest tests/Feature/CreateRoleCommandTest.php # Interactive commands
Test Coverage
- RoleValidator (24 tests) - Caching, validation, and hierarchy calculations
- Commands (17 tests) - Interactive role creation and installation
- Database (16 tests) - Role assignments and model relationships
- Unit Tests (15 tests) - Core role logic and factory methods
- Edge Cases (20+ scenarios) - File corruption, invalid states, race conditions
Requirements
- PHP 8.1+ - Modern language features
- Laravel 11.0+ | 12.0+ - Framework compatibility
- Database with JSON support - MySQL 5.7+, PostgreSQL 9.5+, SQLite 3.1+
Contributing
I welcome contributions! Please see our Contributing Guide for details.
Ways to help:
- ๐ Report bugs and edge cases
- ๐ Improve documentation
- ๐งช Write additional tests
- ๐ก Suggest new features
- ๐ Share your use cases
- ๐ณ๏ธ Vote on roadmap features
License
MIT License. Free for commercial and personal use.
Porter - Keep it simple, keep it fast, keep it focused. ๐ช
Built with โค๏ธ for developers who appreciate clean architecture and domain-driven design.