Weave 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

Logical Authorization Bundle Laravel Package

ordermind/logical-authorization-bundle

A Laravel package for building logical, composable authorization rules. Combine gates, policies, and custom conditions into readable checks, keep permission logic centralized and testable, and integrate cleanly with the framework's existing auth system.

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing to know is that this is a Symfony 4 bundle, not a Laravel package. You won't composer require it into a Laravel app and have it "just work" — there is no service provider, no facade, no Gate integration. So "getting started" is really about deciding which of two paths you're on:

  1. You're actually in a Symfony 4 app (rare in 2025, but exists): composer require ordermind/logical-authorization-bundle, register Ordermind\LogicalAuthorizationBundle\LogicalAuthorizationBundle in config/bundles.php, then look first at config/packages/logical_authorization.yaml and the AuthorizationManager service. First use case: protect a controller action with @RoutePermission(permissions={"and", "logged_in"}) or call $authManager->checkPermission($permission) from a controller.
  2. You're a Laravel dev mining it for patterns: skip the install. Clone the repo, read src/Logic/ (LogicEvaluator, LogicExpression) and src/Permissions/ (PermissionProvider, AuthorizationManager). That's ~500 LOC of genuinely portable code — the logical expression DSL is the entire value proposition, and it drops cleanly into a Laravel Gate::define() callback or a custom Authorizer service.

The mental model to hold: permissions are data, defined in YAML or attributes, and each one is a nested logical expression (["and", ["or", "editor", "owner"], ["not", "banned"]]). The AuthorizationManager is the single entry point that evaluates them in context.

Implementation Patterns

Logical expressions are the core. Everything revolves around operators: and, or, not, plus leaf terms that resolve to booleans, role checks, or context comparisons. Expressions nest arbitrarily, so you compose coarse policies (route-level) from fine-grained ones (field-level) without duplicating rules.

Permission providers organize policy. You register named providers in YAML, each mapping permission names to expressions. A controller asks checkPermission("post.edit", $post), and the provider resolves the chain. This is the equivalent of a Laravel Policy class but defined declaratively rather than as PHP methods — which means non-developers can edit policy, but you lose IDE support and static analysis.

Three enforcement layers, use all three:

  • Route: @RoutePermission attribute on controller actions — the closest analog to Laravel's ->middleware('can:...').
  • Entity: @PermissionProvider on a Doctrine entity — like a policy attached to a model.
  • Field: @PermissionConfigForField + @Permission on properties, with canSeeField() / canEditField() at runtime — useful for serializing responses (hide fields the caller can't read) which Laravel doesn't have a first-class story for.

Context passing. Expressions reference @user.id, @user.roles, and the current entity via @this.*. The AuthorizationManager accepts arbitrary context arguments, so the same permission can be evaluated against different users/entities in a single request — useful for admin-preview features ("what would this user see?").

Chaining with existing security. The bundle is designed to sit alongside Symfony's Voters rather than replace them; in a Laravel port you'd have Gate::before() delegate to the expression evaluator, and fall through to native policies for anything not expression-driven.

Gotchas and Tips

  • Symfony 4 only. The dependency constraints (Symfony 4.x, Doctrine Annotations) don't resolve cleanly against Symfony 5/6. There are 23 stars and 0 dependents for a reason — treat it as reference code, not a maintained dependency.
  • YAML booleans bite. true and false in YAML parse as PHP booleans, not the strings the evaluator expects. Quote them: "true" / "false". Same for numeric-looking permission names.
  • A flat list is not an AND. ["a", "b"] does not mean "a and b" — the evaluator expects an operator first. Unrecognized shapes typically fail closed (deny), which means a typo silently locks users out rather than erroring loudly.
  • @ reference resolution is context-sensitive. @this.field only works when a subject entity is passed; @user.id requires the user in context. Missing context keys fail — surface a clear exception in your port rather than returning false, or you'll spend hours debugging authorization that looks correct but silently denies.
  • null is not false for field checks. Partial expressions can return null; canSeeField() treats that inconsistently across versions. Normalize null → false at the boundary in any port.
  • Container caching. In Symfony, YAML permission changes need bin/console cache:clear (sometimes cache:warmup) — config is compiled into the container. Easy to think a rule change didn't apply when really you're hitting stale cache.
  • Debugging tools worth knowing: bin/console debug:config logical_authorization dumps the parsed provider graph, and $authManager->getPermissionProvider($name) gives you the raw provider if you need to trace an evaluation. If you port it, build a single explain(string $permission, array $context): array method that returns the evaluation tree — you'll use it constantly.
  • Extension point if you do adopt it: LogicEvaluatorInterface is tagged (in Laravel terms, register an implementation and bind the interface) — you can add domain operators like "owned_by" without forking. Do this before you start hand-writing compound expressions everywhere.
  • Laravel port sketch: bind a singleton AuthorizationManager, load provider YAML in a service provider (use config/logical_authorization.php), and wire Gate::before(fn($user, $ability, $args) => $manager->check($ability, $user, ...$args)). Ship a @canSee('post.body', $post) Blade directive for field-level checks. That's the whole integration surface.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource