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

Resource Access Laravel Package

at/resource-access

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require at/resource-access
    

    Add the bundle to config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 2/3):

    AT\ResourceAccessBundle\ATResourceAccessBundle::class => ['all' => true],
    
  2. Configure Doctrine: Update config/packages/doctrine.yaml (Symfony 4+) or config.yml (Symfony 2/3):

    doctrine:
        orm:
            resolve_target_entities:
                AT\ResourceAccessBundle\Entity\Requester: App\Entity\User
    
  3. Implement RequesterInterface: Extend your User entity:

    use AT\ResourceAccessBundle\Model\RequesterInterface;
    
    class User implements RequesterInterface
    {
        // ...
    }
    
  4. Create a Resource Entity: Implement ResourceInterface and embed the Resource entity:

    use AT\ResourceAccessBundle\Model\ResourceInterface;
    use AT\ResourceAccessBundle\Entity\Resource;
    
    class MyResource implements ResourceInterface
    {
        /**
         * @ORM\OneToOne(targetEntity="AT\ResourceAccessBundle\Entity\Resource", cascade={"persist"})
         */
        private $resource;
    
        public function __construct()
        {
            $this->resource = new Resource();
        }
    
        public function getResource(): Resource
        {
            return $this->resource;
        }
    }
    
  5. Define Role Hierarchy: Configure in config/packages/at_resource_access.yaml (Symfony 4+):

    at_resource_access:
        resources:
            App\Entity\MyResource:
                role_hierarchy:
                    ROLE_ADMIN: [ROLE_EDIT]
                    ROLE_EDIT: [ROLE_READ]
    
  6. Update Schema:

    php bin/console doctrine:schema:update --force
    

First Use Case

Grant access to a resource in a controller:

use AT\ResourceAccessBundle\Manager\ResourceAccessManagerInterface;

class MyResourceController extends AbstractController
{
    public function grantAccess(ResourceAccessManagerInterface $manager, User $user, MyResource $resource)
    {
        $manager->grantAccess($user, $resource, ['ROLE_EDIT']);
        return new Response('Access granted!');
    }
}

Implementation Patterns

Common Workflows

  1. Granting Access:

    // Single role
    $manager->grantAccess($user, $resource, ['ROLE_READ']);
    
    // Multiple roles
    $manager->grantAccess($user, $resource, ['ROLE_READ', 'ROLE_EDIT'], $grantedByUser);
    
  2. Checking Access:

    // For logged-in user (auto-resolves from security context)
    $manager->isGranted('ROLE_READ', $resource);
    
    // For specific user
    $manager->isGranted('ROLE_EDIT', $resource, $user);
    
  3. Bulk Updates:

    // Replace all roles
    $manager->updateAccessLevels($user, $resource, ['ROLE_ADMIN']);
    
    // Remove specific roles
    $manager->removeAccessLevels($user, $resource, ['ROLE_READ']);
    
  4. Revoking All Access:

    $manager->removeAccess($user, $resource);
    

Integration Tips

  • Event Listeners: Trigger access checks in pre-persist/update listeners:

    public function preUpdate(LifecycleEventArgs $args)
    {
        $resource = $args->getObject();
        $user = $this->security->getUser();
    
        if (!$this->manager->isGranted('ROLE_EDIT', $resource, $user)) {
            throw new AccessDeniedException();
        }
    }
    
  • Voters: Extend AbstractResourceVoter for custom logic:

    use AT\ResourceAccessBundle\Security\Voter\AbstractResourceVoter;
    
    class MyResourceVoter extends AbstractResourceVoter
    {
        protected function supports(string $attribute, $subject): bool
        {
            return $attribute === 'EDIT' && $subject instanceof MyResource;
        }
    
        protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
        {
            return $this->manager->isGranted('ROLE_EDIT', $subject, $token->getUser());
        }
    }
    
  • Forms: Dynamically populate role selections based on hierarchy:

    $form->add('roles', EntityType::class, [
        'class' => Role::class,
        'choices' => $this->getAllowedRoles($resource),
    ]);
    
  • APIs: Use isGranted() in API controllers to validate requests:

    public function update(MyResource $resource, Request $request)
    {
        if (!$this->manager->isGranted('ROLE_EDIT', $resource)) {
            return $this->json(['error' => 'Unauthorized'], 403);
        }
        // ...
    }
    

Gotchas and Tips

Pitfalls

  1. Role Hierarchy Conflicts:

    • Issue: Undefined parent-child relationships cause unexpected access.
    • Fix: Explicitly define all hierarchies in config.yml. Example:
      ROLE_ADMIN: [ROLE_EDIT, ROLE_READ]
      ROLE_EDIT:  [ROLE_READ]
      
    • Debug: Use bin/console debug:role-hierarchy (if available) or log the hierarchy:
      $manager->getRoleHierarchy($resource);
      
  2. Circular Dependencies:

    • Issue: Forgetting to embed the Resource entity in your custom resource causes null references.
    • Fix: Always initialize $resource in the constructor and map it as @OneToOne.
  3. Doctrine Proxy Issues:

    • Issue: Lazy-loaded Resource entities fail in voters/listeners.
    • Fix: Initialize the Resource entity eagerly or use getResource()->getId() to trigger loading.
  4. Security Context:

    • Issue: isGranted() without a user parameter fails if no user is logged in.
    • Fix: Pass $user explicitly or handle null:
      $user = $this->security->getUser() ?: new AnonymousUserToken();
      
  5. Schema Updates:

    • Issue: Forgetting to run doctrine:schema:update after adding new resources.
    • Fix: Add a post-install script to your composer.json:
      "scripts": {
          "post-install-cmd": [
              "php bin/console doctrine:schema:update --force"
          ]
      }
      

Debugging Tips

  1. Log Access Decisions:

    $manager->isGranted('ROLE_READ', $resource, $user, true); // Enable debug mode
    
  2. Inspect Role Hierarchy:

    $hierarchy = $manager->getRoleHierarchy($resource);
    var_dump($hierarchy);
    
  3. Check Granted Roles:

    $grantedRoles = $manager->getAccessLevels($user, $resource);
    var_dump($grantedRoles);
    
  4. Symfony Profiler:

    • Add a data collector to visualize access decisions:
      use AT\ResourceAccessBundle\DataCollector\ResourceAccessDataCollector;
      
      services:
          app.resource_access.data_collector:
              class: AT\ResourceAccessBundle\DataCollector\ResourceAccessDataCollector
              arguments: ['@resource_access.manager']
              tags: ['data_collector']
      

Extension Points

  1. Custom Storage:

    • Override the ResourceAccessStorage interface to use a non-Doctrine backend (e.g., Redis):
      use AT\ResourceAccessBundle\Storage\ResourceAccessStorageInterface;
      
      class RedisResourceAccessStorage implements ResourceAccessStorageInterface
      {
          // Implement methods to use Redis
      }
      
    • Register as a service:
      services:
          resource_access.storage:
              class: App\Storage\RedisResourceAccessStorage
      
  2. Dynamic Role Hierarchies:

    • Fetch hierarchies from a database or API:
      $hierarchy = $this->hierarchyRepository->findForResource($resource);
      $manager->setRoleHierarchy($resource, $hierarchy);
      
  3. Bulk Operations:

    • Create a command to grant access to multiple users/resources:
      use Symfony\Component\Console\Command\Command;
      use Symfony\Component\Console\Input\InputInterface;
      use Symfony\Component\Console\Output\OutputInterface;
      
      class GrantAccessCommand extends Command
      {
          protected function execute(InputInterface $input, OutputInterface $output)
          {
              $users = $this->userRepository->findBy(['role' => 'ROLE_ADMIN']);
              $resource = $this->resourceRepository->find(1);
      
              foreach ($users as $user) {
                  $this->
      
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
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
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