orbitale/permissions-bundle
Symfony bundle for managing permissions and access control with simple annotations. Define permissions in YAML, attach them to controller actions, and check user rights through a lightweight, cache-friendly API that integrates cleanly into existing Symfony security setups.
This is a Symfony bundle, not a Laravel package. It will not install or run in a Laravel application. If you are a Laravel developer, the direct answer is: do not use this package. Use Laravel’s native Gate/Policy system or a maintained package like spatie/laravel-permission. The rest of this assessment explains the bundle for Symfony contexts and how to translate its single-voter pattern to Laravel if you are evaluating it for a migration or cross-framework project.
For a Symfony 3/4 app (the bundle’s last release was 2017):
composer require orbitale/permissions-bundle
Register Orbitale\PermissionsBundle\OrbitalePermissionsBundle in AppKernel.php or bundles.php.
Define permissions in config/packages/orbitale_permissions.yaml (or config.yml):
orbitale_permissions:
permissions:
edit_post:
roles: [ROLE_ADMIN]
view_post:
roles: [ROLE_USER, ROLE_ADMIN]
Check in a controller: $this->isGranted('permissions', 'edit_post') or in Twig: {% if permissions('edit_post') %}.
First use case: gate a controller action or template block behind a named permission rather than a raw role. This centralizes the role-to-permission mapping in config and lets you change access without touching code.
For Laravel, the equivalent first use case is:
Gate::define('edit-post', function (User $user) {
return $user->hasRole('admin');
});
and @can('edit-post').
Config-driven permission registry. Define every permission in one YAML file and map it to one or more roles. The bundle’s single voter reads this mapping. This is the core value: you stop scattering ROLE_ADMIN checks and instead use stable permission names like edit_post.
Check permissions, not roles, in controllers and Twig. Use isGranted('permissions', 'permission_name') in PHP or permissions('permission_name') in Twig. Avoid checking ROLE_* directly; that defeats the decoupling.
Combine with object-level voters when needed. The bundle provides a single global voter for role-based permissions. For record-level checks (e.g., “can this user edit this post?”), keep a separate Symfony voter or use Laravel policies. Do not try to force dynamic object logic into the config mapping.
Laravel translation of the single-voter pattern. If you like the idea but are on Laravel, replicate it with a config file and one Gate closure:
// config/permissions.php
return [
'edit_post' => ['roles' => ['admin']],
'view_post' => ['roles' => ['user', 'admin']],
];
Gate::define('permission', function (User $user, string $permission) {
$roles = config("permissions.$permission.roles", []);
return $user->hasAnyRole($roles);
});
Then use @can('permission', 'edit_post') or Gate::allows('permission', 'edit_post'). This is a direct equivalent of the bundle’s approach. Avoid Gate::before for this because it bypasses other gates; use a dedicated ability name.
Workflow. Add a new permission to config, assign it to roles, then check it in code. No new voter classes, no code changes for role re-assignment. That is the day-to-day leverage in a Symfony app.
bin/console cache:clear. In Laravel, if you replicate the pattern, remember php artisan config:cache in production; in development it is fine.PermissionVoter with the attribute permissions. If a check fails, verify the user actually has one of the mapped roles and that role hierarchy is not masking the result. In Laravel, use Gate::inspect() or log inside the Gate closure.edit_post, publish_article) not role names (ROLE_ADMIN). This is the same advice as for Laravel Gates and makes the config mapping meaningful.Security service or use loginUser() in functional tests. In Laravel, use actingAs() with roles and Gate::shouldReceive() when unit-testing the permission gate.How can I help you explore Laravel packages today?