Skip to content

Add Role Inference, Lazy Abilities, and Ability Voting to Guard#4

Merged
techmahedy merged 2 commits intodoppar:1.xfrom
techmahedy:techmahedy-1.x
Mar 10, 2026
Merged

Add Role Inference, Lazy Abilities, and Ability Voting to Guard#4
techmahedy merged 2 commits intodoppar:1.xfrom
techmahedy:techmahedy-1.x

Conversation

@techmahedy
Copy link
Copy Markdown
Member

Add Role Inference, Lazy Abilities, and Ability Voting to Guard

Three new authorization features. Each adds a single registration method and zero breaking changes.


Role Inference — Guard::roles()

Define a role map once. Guard reads $user->role and grants matching abilities automatically.

Guard::roles([
    'admin'  => ['manage-users', 'post.*'],
    'editor' => ['post.create', 'post.edit'],
    'viewer' => ['post.view'],
]);

// User with role === 'editor' — no Guard::define() needed
Guard::allows('post.create'); // true
Guard::allows('manage-users'); // false

Lazy Abilities — Guard::lazy()

Defers callback evaluation until the ability is actually checked. Zero cost if never reached in a request.

Guard::lazy('compliance-check', function (User $user) {
    return ExternalComplianceService::verify($user->id); // never called unless checked
});

// Somewhere deep in a controller — only called if execution reaches here
Guard::allows('compliance-check'); // ExternalComplianceService::verify() runs here, once

Ability Voting — Guard::vote()

Multiple independent voters decide an ability. Each returns true (grant), false (deny), or null (abstain). Supports majority and unanimous strategies.

Guard::vote('publish-post', [
    fn(User $user, Post $post) => $user->isEditor,
    fn(User $user, Post $post) => $post->isReviewed,
    fn(User $user, Post $post) => !$post->isBanned,
], strategy: 'unanimous'); // all three must agree

Guard::allows('publish-post', $post); // false if any voter returns false

Files changed: Authorizer.php, Guard.php
Tests: RoleLazyVoteTest.php — 60 new assertions, all passing

@techmahedy techmahedy merged commit 1b521e2 into doppar:1.x Mar 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant