Installation
composer require effiana/acl-bundle
Add to config/bundles.php (Symfony 4+):
return [
// ...
Effiana\ACLBundle\EffianaACLBundle::class => ['all' => true],
];
Database Migration
Run migrations to create ACL tables (check src/Resources/migrations/ for schema):
php bin/console doctrine:migrations:migrate
First Use Case
Define a resource (e.g., Post) and assign permissions:
// src/Controller/PostController.php
use Effiana\ACLBundle\Annotation\SecureResource;
class PostController extends AbstractController {
/**
* @SecureResource("post", "edit")
*/
public function edit(Post $post) {}
}
Basic Configuration
Override default settings in config/packages/effiana_acl.yaml:
effiana_acl:
resources: ['post', 'user'] # Define allowed resources
default_role: 'ROLE_USER'
Role-Based Access Control (RBAC) Integration Combine with Symfony’s security roles:
# config/packages/security.yaml
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/post/edit, roles: [ROLE_USER, ROLE_EDITOR] }
Dynamic Permission Checks Use the ACL service in controllers/services:
use Effiana\ACLBundle\Service\ACLService;
class PostService {
public function __construct(private ACLService $acl) {}
public function canEdit(Post $post, User $user) {
return $this->acl->isGranted('post', 'edit', $user);
}
}
Resource Hierarchy
Define parent-child relationships (e.g., Category → Post):
$acl->allow('category:1', 'view', 'ROLE_USER');
$acl->allow('post:1', 'edit', 'ROLE_EDITOR'); // Inherits 'view' from category
Event-Driven Permissions
Listen for ACL events (e.g., acl.resource.created):
// src/EventListener/AclListener.php
public function onResourceCreated(ResourceCreatedEvent $event) {
$event->getResource()->addPermission('view', 'ROLE_USER');
}
Symfony Forms: Restrict form fields based on ACL:
$builder->add('title', TextType::class, [
'disabled' => !$this->acl->isGranted('post', 'edit'),
]);
API Platform: Use @SecureResource on API entities:
# config/api_platform/resources.yaml
App\Entity\Post:
collectionOperations:
get:
method: 'GET'
security: 'is_granted("post", "view")'
Doctrine Lifecycle: Auto-apply ACL on entity save:
// src/Entity/Post.php
use Effiana\ACLBundle\Traits\ACLAware;
class Post {
use ACLAware;
protected function applyACL() {
$this->acl->allow($this, 'view', 'ROLE_USER');
}
}
Caching Headaches ACL rules are cached by default. Clear cache after changes:
php bin/console cache:clear
Override cache lifetime in config:
effiana_acl:
cache_lifetime: 3600 # 1 hour
Resource Naming Collisions
Use fully qualified names (e.g., App\Entity\Post instead of post). Avoid:
@SecureResource("post") // Ambiguous!
Missing Migrations If ACL tables exist but are empty, re-run migrations or manually seed data:
php bin/console doctrine:schema:update --force
Annotation Parsing Issues
Ensure annotations are loaded in composer.json:
"autoload": {
"files": ["vendor/doctrine/annotations/autoload.php"]
}
Check Permissions Dump ACL rules for a resource:
$this->acl->getPermissions('post:1')->dump();
Symfony Profiler
Enable ACL debugging in config/packages/dev/acl.yaml:
effiana_acl:
debug: true
Custom Storage Override the default Doctrine storage:
// src/EffianaACLBundle/DependencyInjection/CompilerPass.php
$container->set('effiana_acl.storage', new CustomStorage());
Permission Providers
Extend PermissionProviderInterface for dynamic rules:
class DynamicPermissionProvider implements PermissionProviderInterface {
public function getPermissions($resource) {
return ['view' => ['ROLE_USER', 'ROLE_ADMIN']];
}
}
Voter Integration Bridge with Symfony’s voter system:
class PostVoter extends AbstractVoter {
public function supports($attribute, $subject) {
return $attribute === 'EDIT_POST' && $subject instanceof Post;
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token) {
return $this->acl->isGranted('post', 'edit', $token->getUser());
}
}
GUI Management Build a CRUD interface for ACL rules using EasyAdmin or AdminLTE:
// src/Controller/AclController.php
public function listRules(AclRepository $repo) {
return $this->render('acl/list.html.twig', [
'rules' => $repo->findAll(),
]);
}
How can I help you explore Laravel packages today?