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

Kalinka Laravel Package

ac/kalinka

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require ac/kalinka:dev-master
    

    Add to composer.json if not using latest dev version.

  2. Define a Base Guard Create an abstract guard class extending AC\Kalinka\Guard\BaseGuard in app/Guards/MyAppBaseGuard.php:

    namespace App\Guards;
    
    use AC\Kalinka\Guard\BaseGuard;
    
    abstract class MyAppBaseGuard extends BaseGuard
    {
        protected function policyAdmin($subject)
        {
            return $subject->isAdmin();
        }
    }
    
  3. Create a Concrete Guard Extend MyAppBaseGuard and define actions (methods prefixed with can):

    namespace App\Guards;
    
    use App\Guards\MyAppBaseGuard;
    
    class UserGuard extends MyAppBaseGuard
    {
        public function canEditProfile($subject)
        {
            return $subject->isAuthenticated();
        }
    }
    
  4. Register the Guard Bind the guard in AppServiceProvider:

    public function register()
    {
        $this->app->singleton('kalinka.guard', function ($app) {
            return new \App\Guards\UserGuard();
        });
    }
    
  5. First Usage Inject the guard into a controller/service and check permissions:

    use AC\Kalinka\Guard\GuardInterface;
    
    class ProfileController extends Controller
    {
        protected $guard;
    
        public function __construct(GuardInterface $guard)
        {
            $this->guard = $guard;
        }
    
        public function edit()
        {
            if ($this->guard->can('editProfile', auth()->user())) {
                return view('profile.edit');
            }
            abort(403);
        }
    }
    

Implementation Patterns

Core Workflows

  1. Role-Based Access Control (RBAC) Define roles in policies and reuse them across guards:

    protected function policyEditor($subject)
    {
        return in_array('editor', $subject->roles);
    }
    
  2. Resource-Specific Permissions Pass resources as subjects to enforce granular control:

    public function canDeletePost($subject, $post)
    {
        return $subject->id === $post->user_id;
    }
    
  3. Combining Policies Use logical operators in guards:

    public function canManageContent($subject)
    {
        return $this->policyAdmin($subject) || $this->policyEditor($subject);
    }
    

Integration Tips

  • Laravel Integration Bind the guard to Laravel’s container and resolve it via dependency injection:

    $this->app->bind('kalinka.guard', function ($app) {
        return new UserGuard($app['auth']->user());
    });
    
  • Middleware Create middleware to check permissions globally:

    namespace App\Http\Middleware;
    
    use Closure;
    use AC\Kalinka\Guard\GuardInterface;
    
    class Authorize
    {
        protected $guard;
    
        public function __construct(GuardInterface $guard)
        {
            $this->guard = $guard;
        }
    
        public function handle($request, Closure $next)
        {
            if (!$this->guard->can('accessDashboard', $request->user())) {
                abort(403);
            }
            return $next($request);
        }
    }
    
  • Dynamic Guards Instantiate guards dynamically based on context (e.g., tenant ID):

    $guard = new UserGuard(auth()->user(), $tenantId);
    
  • Fallback Policies Override BaseGuard's fallbackPolicy() to define default deny/allow behavior:

    protected function fallbackPolicy($action, $subject)
    {
        return false; // Default deny
    }
    

Gotchas and Tips

Pitfalls

  1. Method Naming

    • Policies must start with policy (e.g., policyAdmin).
    • Actions must start with can (e.g., canEditProfile).
    • Gotcha: Underscores in method names (e.g., can_edit_profile) will fail silently.
  2. Subject Type Mismatch

    • Ensure the $subject passed to guards matches what your policies expect (e.g., User model vs. string).
    • Debug Tip: Add a __toString() method to your subject for clarity in logs.
  3. Circular Dependencies

    • Avoid injecting guards into other guards to prevent circular resolution issues.
    • Solution: Pass dependencies explicitly via constructor.
  4. Performance

    • Complex policies with nested checks (e.g., database queries) can slow down authorization.
    • Tip: Cache policy results if the subject/guard combination is static:
      protected $policyCache = [];
      
      protected function policyAdmin($subject)
      {
          $cacheKey = spl_object_hash($subject);
          if (!isset($this->policyCache[$cacheKey]['admin'])) {
              $this->policyCache[$cacheKey]['admin'] = $subject->isAdmin();
          }
          return $this->policyCache[$cacheKey]['admin'];
      }
      

Debugging

  • Enable Logging Extend BaseGuard to log policy evaluations:

    protected function logPolicy($action, $subject, $result)
    {
        \Log::debug("Policy $action for " . $subject->id . ": " . ($result ? 'ALLOWED' : 'DENIED'));
    }
    
  • Test Policies in Isolation Use PHPUnit to test guards independently:

    public function testAdminPolicy()
    {
        $guard = new UserGuard($this->createMockUser(['isAdmin' => true]));
        $this->assertTrue($guard->can('editProfile', $user));
    }
    

Extension Points

  1. Custom Guard Storage Override BaseGuard's getSubject() to fetch users from non-standard sources (e.g., API tokens):

    protected function getSubject($request)
    {
        return $request->bearerToken()->user();
    }
    
  2. Action Metadata Attach metadata to actions (e.g., HTTP methods, descriptions) via traits:

    trait ActionMetadata
    {
        protected $actionMetadata = [
            'editProfile' => ['method' => 'PUT', 'description' => 'Edit user profile'],
        ];
    
        public function getActionMetadata($action)
        {
            return $this->actionMetadata[$action] ?? null;
        }
    }
    
  3. Event Dispatching Trigger events on policy evaluation (e.g., audit logs):

    use Illuminate\Support\Facades\Event;
    
    protected function evaluatePolicy($action, $subject)
    {
        $result = parent::evaluatePolicy($action, $subject);
        Event::dispatch('kalinka.policy.evaluated', [$action, $subject, $result]);
        return $result;
    }
    
  4. Policy Groups Organize policies by grouping guards (e.g., AdminGuard, EditorGuard) and composing them:

    class CompositeGuard extends MyAppBaseGuard
    {
        protected $guards = [];
    
        public function __construct(array $guards)
        {
            $this->guards = $guards;
        }
    
        public function can($action, $subject)
        {
            return any($this->guards, function ($guard) use ($action, $subject) {
                return $guard->can($action, $subject);
            });
        }
    }
    
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