alchemy/acl-bundle
Symfony bundle providing a simple ACL API. Configure object types, alias your UserRepository, and add Redis cache for access tokens. Exposes endpoints to list, upsert, and delete ACEs by user/group, object type/id, with permission masks and wildcards.
Symfony-to-Laravel Adaptability:
App\Models\Publication).mask: 7) into Laravel’s Gate/Policy system via a translation layer (e.g., AclMask::toPolicy($mask)).#[Attribute] or accessors to store metadata (e.g., expires_at) on models.UserRepositoryInterface → User facade).Feature Alignment:
Gate/Policy lacks object-specific rules (e.g., "User X can edit Publication#42").metadata: {status: "draft"}). Aligns with Laravel’s attributes or observers./permissions/aces endpoint can be consumed by Laravel’s HTTP client or exposed via Laravel’s API routes (e.g., Route::prefix('acl')->controller(AclController::class)).Technical Risk:
symfony/* packages (mitigate via composer.json overrides or a micro-service architecture).mask: 7) with Laravel’s Gate::allows().Redis facade can replace Symfony’s cache pool, but token serialization (e.g., accessToken.cache) may need adaptation.Events or disabled if unused.Permission Granularity Needs:
Asset#123") or are role-based rules (e.g., Gate::forUser($user)->allows('edit')) sufficient?Gate/Policy may suffice.Metadata Use Cases:
metadata: {expires_at: "2024-12-31", reason: "client_approval"}.Symfony Dependency Tolerance:
composer.json overrides) or is a full rewrite (e.g., Casbin) preferable?spatie/laravel-permission).API vs. Internal Usage:
Acl::check($user, 'edit', $publication)).Scaling Requirements:
Redis facade.Cache::remember("acl:user:{$userId}:object:{$objectId}", 300, fn() => $this->fetchAces($userId, $objectId));
Laravel Compatibility:
App\Models\Publication).UserRepositoryInterface to Laravel’s User model:
// config/acl.php
'user_repository' => App\Models\User::class,
Events system or disable if unused.Redis facade to configure the accessToken.cache pool:
Cache::extend('accessToken', function () {
return Cache::repository(new RedisStore(config('cache.redis')));
});
Permission System:
Gate logic:
class AclMask {
public static function maskToPermission(int $mask): string {
return match ($mask) {
1 => 'view',
2 => 'edit',
4 => 'delete',
7 => 'full_access',
default => 'custom',
};
}
}
acl_metadata table.acl:metadata:publication:42).API Integration:
Http client to call /permissions/aces:
$aces = Http::get('http://symfony-app/permissions/aces', [
'objectType' => 'publication',
'objectId' => 'pub-42',
]);
Route::put('/acl/ace', [AclController::class, 'updateAce']);
Phase 1: Proof of Concept (2 weeks)
/permissions/ace, /permissions/aces) via Http client.Publication, Asset) to Eloquent models.Phase 2: Laravel Integration (3 weeks)
UserRepositoryInterface with Laravel’s User facade.Gate/Policy logic.Acl::check($user, 'edit', $publication)).Phase 3: API & Admin UI (4 weeks)
/api/acl/aces)./permissions/aces API).| Component | Symfony Implementation | Laravel Equivalent | Risk |
|---|---|---|---|
| ORM | Doctrine | Eloquent | Low |
| User Repository | UserRepositoryInterface |
App\Models\User facade |
Medium (alias needed) |
| Events | Symfony EventDispatcher | Laravel Events |
High (replace/disable) |
| Cache | Redis pool (accessToken.cache) |
Laravel Redis facade |
Low |
| API Endpoints | REST (/permissions/aces) |
Laravel API routes or Http client |
Low |
| Metadata | Symfony Attribute | Laravel #[Attribute] or JSON column |
Medium (custom logic) |
Prerequisites:
Critical Path:
How can I help you explore Laravel packages today?