Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Aclbundle Laravel Package

edweld/aclbundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require edweld/aclbundle
    

    Ensure your composer.json includes "minimum-stability": "dev" if the package is only available in @dev.

  2. Register Bundle Add to app/AppKernel.php:

    new Edweld\AclBundle\EdweldAclBundle(),
    
  3. Configure Doctrine Mappings Update app/config/config.yml:

    doctrine:
        orm:
            entity_managers:
                default:
                    mappings:
                        EdweldAclBundle: ~
    
  4. First Use Case: Define ACL Entities Create a User and Circle entity with ACL annotations:

    // src/AppBundle/Entity/User.php
    use Edweld\AclBundle\Model\AclAwareInterface;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity
     * @ORM\Table(name="users")
     */
    class User implements AclAwareInterface
    {
        // ... fields ...
    
        /**
         * @ORM\ManyToMany(targetEntity="Circle", inversedBy="users")
         */
        private $circles;
    
        // Implement AclAwareInterface methods
        public function getAclIdentifier() { /* ... */ }
        public function getAclObjectIdentifier() { /* ... */ }
    }
    
    /**
     * @ORM\Entity
     * @ORM\Table(name="circles")
     */
    class Circle implements AclAwareInterface
    {
        // ... fields ...
    
        /**
         * @ORM\ManyToMany(targetEntity="User", mappedBy="circles")
         */
        private $users;
    
        // Implement AclAwareInterface methods
        public function getAclIdentifier() { /* ... */ }
        public function getAclObjectIdentifier() { /* ... */ }
    }
    
  5. Run Migrations

    php bin/console doctrine:schema:update --force
    
  6. Basic ACL Check

    use Edweld\AclBundle\Acl\AclProvider;
    
    $aclProvider = $this->get('edweld_acl.acl_provider');
    $user = $this->getUser(); // Your logged-in user
    $circle = $entityManager->getRepository('AppBundle:Circle')->find(1);
    
    if ($aclProvider->isGranted('VIEW', $user, $circle)) {
        // User can view the circle
    }
    

Implementation Patterns

Workflow: Role-Based Access Control (RBAC) with Dynamic Groups

  1. Define Permissions Extend the Permission class or use constants:

    // src/AppBundle/Entity/Permission.php
    use Edweld\AclBundle\Model\Permission;
    
    class AppPermission extends Permission
    {
        const VIEW_EVENT = 'VIEW_EVENT';
        const CREATE_EVENT = 'CREATE_EVENT';
    }
    
  2. Assign Permissions via Groups (Circles) Use the AclProvider to attach permissions to groups:

    $circle = $entityManager->find('AppBundle:Circle', 1);
    $user = $entityManager->find('AppBundle:User', 1);
    
    $aclProvider->attachPermission($circle, AppPermission::VIEW_EVENT, $user);
    
  3. Query-Level Filtering Use the QueryHelper to filter entities in repositories:

    // src/AppBundle/Repository/EventRepository.php
    use Edweld\AclBundle\Doctrine\Query\AclQueryHelper;
    
    class EventRepository extends ServiceEntityRepository
    {
        public function findVisibleEvents(User $user)
        {
            $qb = $this->createQueryBuilder('e');
            $aclHelper = $this->getDoctrine()->get('edweld_acl.query_helper');
    
            return $aclHelper->addAclFilter($qb, $user, 'VIEW_EVENT')
                ->getQuery()
                ->getResult();
        }
    }
    
  4. Controller Integration

    // src/AppBundle/Controller/EventController.php
    public function indexAction(User $user)
    {
        $events = $this->getDoctrine()
            ->getRepository('AppBundle:Event')
            ->findVisibleEvents($user);
    
        return $this->render('event/index.html.twig', ['events' => $events]);
    }
    

Integration Tips

  • Symfony Security Integration Override AccessDecisionManager to use AclProvider for authorization:

    # app/config/security.yml
    security:
        access_decision_manager:
            strategy: affirmative
            allow_if_all_abstain: false
    

    Create a custom AclVoter:

    use Edweld\AclBundle\Acl\AclProvider;
    
    class AclVoter extends AbstractVote
    {
        private $aclProvider;
    
        public function __construct(AclProvider $aclProvider)
        {
            $this->aclProvider = $aclProvider;
        }
    
        protected function supports($attribute, $object)
        {
            return $attribute === 'VIEW_EVENT' && $object instanceof Event;
        }
    
        protected function voteOnAttribute($attribute, $object, TokenInterface $token)
        {
            return $this->aclProvider->isGranted($attribute, $token->getUser(), $object);
        }
    }
    
  • Event Listeners for Dynamic Permissions Use listeners to update ACLs when entities change:

    // src/AppBundle/EventListener/AclListener.php
    use Edweld\AclBundle\Acl\AclProvider;
    use Doctrine\Common\EventSubscriber;
    
    class AclListener implements EventSubscriber
    {
        private $aclProvider;
    
        public function __construct(AclProvider $aclProvider)
        {
            $this->aclProvider = $aclProvider;
        }
    
        public function getSubscribedEvents()
        {
            return [
                'postPersist',
                'postUpdate',
            ];
        }
    
        public function postPersist(LifecycleEventArgs $args)
        {
            $entity = $args->getObject();
            if ($entity instanceof Circle) {
                $this->aclProvider->attachPermission($entity, AppPermission::VIEW_EVENT, $entity->getCreator());
            }
        }
    }
    

Gotchas and Tips

Pitfalls

  1. SQL Query Complexity

    • The query-level filtering adds complexity to SQL queries. Test performance under load, especially with deep relationships.
    • Workaround: Use DISTINCT or optimize joins if queries become slow:
      $qb->distinct()->leftJoin('e.circle', 'c');
      
  2. Circular Dependencies

    • If User and Circle have bidirectional relationships, ensure AclAwareInterface methods (getAclIdentifier, getAclObjectIdentifier) return consistent values to avoid infinite loops in ACL checks.
    • Tip: Use unique identifiers like id or composite keys:
      public function getAclIdentifier() { return $this->id; }
      public function getAclObjectIdentifier() { return $this->circle->id; }
      
  3. Permission Inheritance

    • The package does not natively support hierarchical permissions (e.g., "ADMIN" inherits "EDIT"). Implement manually:
      public function isGranted($permission, User $user, $object)
      {
          if ($permission === 'EDIT' && $this->isAdmin($user)) {
              return true;
          }
          return parent::isGranted($permission, $user, $object);
      }
      
  4. Debugging ACL Checks

    • Enable SQL logging to debug query filters:
      # app/config/config.yml
      doctrine:
          dbal:
              logging: true
              logging_format: '%%sql%%'
      
    • Use AclProvider::debug() to log ACL decisions:
      $aclProvider->debug(true);
      

Tips

  1. Use Enums for Permissions Define permissions as constants or enums to avoid typos:

    final class EventPermission
    {
        public const VIEW = 'VIEW_EVENT';
        public const CREATE = 'CREATE_EVENT';
    }
    
  2. Batch Permission Updates For bulk operations (e.g., adding users to a circle), use transactions:

    $entityManager->beginTransaction();
    try {
        foreach ($users as $user) {
            $aclProvider->attachPermission($circle, EventPermission::VIEW, $user);
        }
        $entityManager->flush();
        $entityManager->commit();
    } catch (\Exception $e) {
        $entityManager->rollback();
        throw $e;
    }
    
  3. Cache ACL Decisions Cache frequent ACL checks (e.g., in a Symfony\Component\HttpKernel\CacheWarmer):

    $cache = $this->get('cache.app');
    $cacheKey = sprintf('acl_%s_%s_%s', $user->getId(), get_class
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware