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

Acl Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup for Laravel Integration

  1. Install the Bundle (via Composer):

    composer require alchemy/acl-bundle
    

    Note: Requires Symfony components. Use composer require symfony/options-resolver symfony/attribute if missing.

  2. Configure Objects (in config/acl.php):

    return [
        'objects' => [
            'publication' => App\Models\Publication::class,
            'asset' => App\Models\Asset::class,
        ],
    ];
    
  3. Alias User Repository (in AppServiceProvider):

    public function register()
    {
        $this->app->bind(
            Alchemy\AclBundle\Repository\UserRepositoryInterface::class,
            App\Repositories\UserRepository::class
        );
    }
    
  4. Set Up Redis Cache (in .env):

    CACHE_DRIVER=redis
    REDIS_HOST=127.0.0.1
    
  5. First Use Case: Check Permissions Use the API endpoint via Laravel’s HTTP client:

    $response = Http::get('http://symfony-app/permissions/aces', [
        'objectType' => 'publication',
        'objectId' => 'pub-123',
    ]);
    

Implementation Patterns

Workflow: Managing Permissions

  1. Define Permissions via API Grant a user edit access to a publication:

    Http::put('http://symfony-app/permissions/ace', [
        'userType' => 'user',
        'userId' => 'user-42',
        'objectType' => 'publication',
        'objectId' => 'pub-123',
        'mask' => 2, // Edit permission (binary 010)
        'metadata' => ['reason' => 'editorial_override']
    ]);
    
  2. Check Permissions in Laravel Create a service to proxy API calls:

    class AclService {
        public function hasPermission(string $userId, string $objectType, string $objectId, int $mask): bool
        {
            $aces = Http::get('http://symfony-app/permissions/aces', [
                'userType' => 'user',
                'userId' => $userId,
                'objectType' => $objectType,
                'objectId' => $objectId,
            ])->json();
    
            return collect($aces)->contains(fn ($ace) => $ace['mask'] & $mask);
        }
    }
    
  3. Integrate with Eloquent Models Add a trait to models for permission checks:

    trait HasAclPermissions {
        public function userCan($userId, $permissionMask)
        {
            return app(AclService::class)->hasPermission(
                $userId,
                $this->getAclObjectType(),
                $this->id,
                $permissionMask
            );
        }
    }
    

Workflow: Metadata-Driven Rules

  1. Attach Metadata to Permissions

    Http::put('http://symfony-app/permissions/ace', [
        'userType' => 'user',
        'userId' => 'user-42',
        'objectType' => 'publication',
        'objectId' => 'pub-123',
        'mask' => 4, // Publish permission (binary 100)
        'metadata' => [
            'expires_at' => now()->addDays(7)->toDateTimeString(),
            'department' => 'editorial'
        ]
    ]);
    
  2. Validate Metadata in Laravel Check if a permission is expired:

    $ace = Http::get('http://symfony-app/permissions/aces', [
        'userType' => 'user',
        'userId' => 'user-42',
        'objectType' => 'publication',
        'objectId' => 'pub-123',
    ])->json()[0];
    
    if (isset($ace['metadata']['expires_at']) &&
        strtotime($ace['metadata']['expires_at']) < time()) {
        throw new \Exception('Permission expired');
    }
    

Workflow: Group-Based Permissions

  1. Grant Permissions to Groups

    Http::put('http://symfony-app/permissions/ace', [
        'userType' => 'group',
        'userId' => 'group-editors',
        'objectType' => 'publication',
        'objectId' => null, // Applies to all publications
        'mask' => 2, // Edit permission
    ]);
    
  2. Check Group Membership in Laravel Extend the AclService to resolve group memberships:

    public function userInGroup($userId, $groupId): bool
    {
        // Implement logic to check if user belongs to group
        return true;
    }
    
    public function hasGroupPermission($userId, $groupId, $objectType, $objectId, $mask): bool
    {
        $aces = Http::get('http://symfony-app/permissions/aces', [
            'userType' => 'group',
            'userId' => $groupId,
            'objectType' => $objectType,
            'objectId' => $objectId,
        ])->json();
    
        return $this->userInGroup($userId, $groupId) &&
               collect($aces)->contains(fn ($ace) => $ace['mask'] & $mask);
    }
    

Gotchas and Tips

Pitfalls

  1. Symfony Component Conflicts

    • Issue: Symfony’s Attribute or OptionsResolver may conflict with Laravel’s autoloading.
    • Fix: Exclude Symfony classes from Laravel’s discovery:
      "extra": {
          "laravel": {
              "dont-discover": ["symfony/*"]
          }
      }
      
  2. Mask vs. Named Permissions

    • Issue: Laravel’s Gate uses named methods (can('edit')), while this bundle uses numeric masks (mask: 2).
    • Fix: Create a mapping helper:
      class PermissionMask {
          public const READ = 1;
          public const EDIT = 2;
          public const PUBLISH = 4;
      
          public static function toMask(string $permission): int
          {
              return match ($permission) {
                  'read' => self::READ,
                  'edit' => self::EDIT,
                  'publish' => self => PUBLISH,
                  default => 0,
              };
          }
      }
      
  3. Metadata Serialization

    • Issue: Symfony’s metadata system may not align with Laravel’s JSON serialization.
    • Fix: Normalize metadata in Laravel:
      $metadata = json_decode($ace['metadata'], true);
      
  4. Redis Cache Configuration

    • Issue: The bundle expects a Redis pool named accessToken.cache.
    • Fix: Configure Laravel’s cache to match:
      Cache::extend('accessToken', function () {
          return Cache::repository(new RedisStore(config('cache.redis')));
      });
      
  5. Null ObjectId/Null UserId

    • Issue: objectId: null or userId: null applies permissions globally, which may be unintended.
    • Fix: Validate in Laravel before proxying API calls:
      if ($objectId === null) {
          throw new \InvalidArgumentException('Global permissions not allowed');
      }
      

Debugging Tips

  1. Inspect ACEs Use the /permissions/aces endpoint to debug:

    curl http://symfony-app/permissions/aces?objectType=publication&objectId=pub-123
    
  2. Log API Responses Add logging in your AclService:

    \Log::debug('ACL API Response', ['response' => $response->json()]);
    
  3. Test Mask Calculations Verify bitwise operations:

    // Check if user has READ (1) or EDIT (2) permissions
    $hasPermission = ($ace['mask'] & (PermissionMask::READ | PermissionMask::EDIT)) > 0;
    
  4. Handle API Failures Retry transient failures:

    try {
        $response = Http::retry(3, 100)->get('...');
    } catch (\Throwable $e) {
        \Log::error('ACL API failed', ['error' => $e->getMessage()]);
        return false;
    }
    

Extension Points

  1. Custom Metadata Validation Extend the bundle’s metadata handling by adding Laravel validation rules:

    use Illuminate\Validation\Rule;
    
    $validator = Validator::make($metadata, [
        'expires_at' => ['required', 'date', Rule::unique('permissions_metadata')->where(fn ($query) => $query->where('object_id', $objectId))],
    ]);
    
  2. **Event Listeners for

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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor