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

User Permission Bundle Laravel Package

effinix/user-permission-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require effinix/user-permission-bundle
    

    Register the bundle in config/bundles.php:

    return [
        // ...
        Effinix\UserPermissionBundle\EffinixUserPermissionBundle::class => ['all' => true],
    ];
    
  2. Configure Permissions Define permissions in config/packages/effinix_user_permission.yaml:

    effinix_user_permission:
        permission_store:
            permissions:
                - 'login'
                - 'admin_dashboard'
                - 'edit_profile'
    
  3. First Use Case Protect a route with @RequirePermission:

    #[Route('/dashboard', name: 'dashboard')]
    #[RequirePermission('admin_dashboard')]
    public function dashboard(): Response
    {
        return new Response('Welcome to the dashboard!');
    }
    
  4. Implement UserInterface Extend your User entity:

    class User implements UserInterface
    {
        public function hasPermission(string $permission): bool
        {
            return in_array($permission, $this->getPermissions());
        }
    
        public function getPermissions(): array
        {
            return ['login', 'edit_profile']; // Example permissions
        }
    }
    
  5. Test in Development Enable caching for performance (default: true):

    when@dev:
        effinix_user_permission:
            do_cache: true
    

Implementation Patterns

Workflows

  1. Role-Based Permissions Use hasPermission() to dynamically assign permissions:

    if ($user->hasPermission('admin_dashboard')) {
        return $this->renderDashboard();
    }
    
  2. Permission Groups Group permissions in config for reusability:

    effinix_user_permission:
        permission_store:
            permissions:
                - 'user.*'  # Wildcard for user-related actions
                - 'admin.*'
    
  3. Invokable Controllers Protect invokable controllers (Symfony 6.3+):

    #[AsController]
    #[RequirePermission('edit_profile')]
    class ProfileController
    {
        public function __invoke(): Response
        {
            return new Response('Profile updated!');
        }
    }
    
  4. Middleware Integration Combine with Symfony’s middleware for global checks:

    // src/Kernel.php
    protected function build(RequestContext $requestContext): void
    {
        $requestContext->addListener(
            new PermissionMiddleware($this->getPermissionStore())
        );
    }
    
  5. API Resource Protection Use with API Platform or API Resource controllers:

    #[ApiResource(operations: [
        new Get(collection: false, requirements: ['id' => '\d+']),
        new Post(denormalizationContext: ['groups' => ['admin']]),
        new Put(denormalizationContext: ['groups' => ['admin']]),
    ])]
    #[RequirePermission('admin_edit')]
    class AdminResource
    {
    }
    

Integration Tips

  • Doctrine Integration Fetch permissions from a database table:

    public function getPermissions(): array
    {
        return $this->permissionRepository->findBy(['user' => $this]);
    }
    
  • Symfony Security Component Bridge with Symfony’s security system:

    // src/Security/Voter/PermissionVoter.php
    class PermissionVoter extends Voter
    {
        public function voteOnAttribute(
            string $attribute,
            $subject,
            UserInterface $user
        ): bool {
            return $user->hasPermission($attribute);
        }
    }
    
  • Event Listeners Log permission checks:

    // src/EventListener/PermissionListener.php
    class PermissionListener implements KernelEventSubscriber
    {
        public function onKernelController(
            ControllerEvent $event
        ): void {
            $controller = $event->getController();
            if (is_array($controller)) {
                $permission = $controller[0]->getPermission();
                $this->logger->info("Permission checked: {$permission}");
            }
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Caching Issues

    • Clear cache after adding new permissions:
      php bin/console cache:clear
      
    • Disable caching in dev if permissions change dynamically:
      when@dev:
          effinix_user_permission:
              do_cache: false
      
  2. Permission Store Provider

    • The provider key in config is required but undocumented. Use a custom provider if needed:
      effinix_user_permission:
          permission_store:
              provider: 'custom_provider_id'
      
  3. Attribute Conflicts

    • Ensure @RequirePermission is placed before @Route or @AsController to avoid conflicts.
  4. Wildcard Permissions

    • Wildcards (e.g., user.*) are not supported by default. Implement custom logic in hasPermission():
      public function hasPermission(string $permission): bool
      {
          return str_starts_with($permission, 'user.') &&
                 $this->isUserRole();
      }
      
  5. Invokable Controllers

    • The bundle may not auto-detect invokable controllers in older Symfony versions. Explicitly annotate:
      #[AsController]
      #[RequirePermission('invokable_action')]
      class InvokableController
      {
          public function __invoke() { ... }
      }
      

Debugging

  • Check Permissions Dump permissions in a controller:

    dump($this->getUser()->getPermissions());
    
  • Enable Debugging Add a debug listener:

    // src/EventListener/DebugPermissionListener.php
    class DebugPermissionListener implements KernelEventSubscriber
    {
        public function onKernelRequest(RequestEvent $event): void
        {
            if ($event->isMainRequest()) {
                $this->logger->debug(
                    'Permissions checked: ' . implode(', ', $this->getCheckedPermissions())
                );
            }
        }
    }
    

Extension Points

  1. Custom Permission Store Extend PermissionStoreInterface for database-backed permissions:

    class DatabasePermissionStore implements PermissionStoreInterface
    {
        public function hasPermission(UserInterface $user, string $permission): bool
        {
            return $this->entityManager->getRepository(Permission::class)
                ->exists(['user' => $user->getId(), 'name' => $permission]);
        }
    }
    
  2. Dynamic Permissions Override getPermissions() to fetch from an external API:

    public function getPermissions(): array
    {
        $response = $this->httpClient->request('GET', '/api/user/permissions');
        return json_decode($response->getContent(), true);
    }
    
  3. Permission Events Dispatch events for permission changes:

    // src/Event/PermissionChangedEvent.php
    class PermissionChangedEvent extends Event
    {
        public function __construct(private string $permission) {}
        public function getPermission(): string { return $this->permission; }
    }
    
  4. GUI for Permissions Create a CRUD interface for managing permissions:

    // src/Controller/PermissionController.php
    #[Route('/admin/permissions')]
    class PermissionController extends AbstractController
    {
        #[Route('/new', name: 'permission_new')]
        #[RequirePermission('admin_manage_permissions')]
        public function new(Request $request): Response
        {
            // ...
        }
    }
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle