Skip to content

Conversation

@binaryfire
Copy link
Contributor

@binaryfire binaryfire commented Dec 31, 2025

Summary

This PR ports Laravel's #[UsePolicy] attribute to Hypervel, allowing models to declare their authorization policy class using a PHP attribute instead of manual registration.

Changes

New Files

  • src/core/src/Database/Eloquent/Attributes/UsePolicy.php - The attribute class that can be applied to model classes to declare their policy

Modified Files

  • src/auth/src/Access/Gate.php - Added getPolicyFromAttribute() method and updated getPolicyFor() to check for the attribute

Test Files

  • tests/Auth/Access/GateTest.php - Added 5 new test cases
  • tests/Auth/Stub/DummyWithUsePolicy.php - Test model with attribute
  • tests/Auth/Stub/DummyWithUsePolicyPolicy.php - Test policy class
  • tests/Auth/Stub/DummyWithoutUsePolicy.php - Test model without attribute
  • tests/Auth/Stub/SubDummyWithUsePolicy.php - Test subclass with attribute

Usage

use Hypervel\Database\Eloquent\Attributes\UsePolicy;

#[UsePolicy(PostPolicy::class)]
class Post extends Model
{
    // ...
}

The Gate will now automatically resolve PostPolicy when authorizing actions on Post models:

Gate::authorize('update', $post); // Uses PostPolicy

Policy Resolution Order

  1. Explicit registration - Gate::policy(Post::class, PostPolicy::class) takes precedence
  2. #[UsePolicy] attribute - Checked if no explicit policy is registered
  3. Subclass fallback - Falls back to parent class policies if no attribute found

Key Differences from #[ObservedBy] / #[ScopedBy]

Aspect ObservedBy / ScopedBy UsePolicy
Implementation location Model traits Gate class
Resolution mechanism Model boots and registers Gate reads at runtime
Inheritance/trait support Collects from parents + traits Single class only
Repeatable Yes No
Pivot model changes needed Yes No

The #[UsePolicy] attribute is simpler because the Gate reads the attribute via reflection at authorization time - no model trait or boot mechanism is required.

Test Plan

  • Policy can be resolved from #[UsePolicy] attribute
  • Works with object instances, not just class names
  • Explicit policy registration takes precedence over attribute
  • Attribute takes precedence over subclass fallback
  • Returns null for classes without the attribute

Port Laravel's UsePolicy attribute to Hypervel, allowing models to
declare their authorization policy class using a PHP attribute.

- Add UsePolicy attribute class in Database\Eloquent\Attributes
- Add getPolicyFromAttribute() method to Gate
- Update getPolicyFor() to check attribute between explicit policies
  and subclass fallback
- Add 5 tests covering attribute resolution, precedence, and edge cases
@binaryfire binaryfire changed the title feat: Add #[UsePolicy] attribute for declarative policy binding feat: Add #[UsePolicy] attribute for declarative policy binding Dec 31, 2025
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