Skip to content

Commit 8da277b

Browse files
[12.x] feat: create UsePolicy attribute (#55882)
* feat: create UsePolicy attribute * formatting --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 70575df commit 8da277b

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

src/Illuminate/Auth/Access/Gate.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
99
use Illuminate\Contracts\Container\Container;
1010
use Illuminate\Contracts\Events\Dispatcher;
11+
use Illuminate\Database\Eloquent\Attributes\UsePolicy;
1112
use Illuminate\Support\Arr;
1213
use Illuminate\Support\Collection;
1314
use Illuminate\Support\Str;
@@ -669,6 +670,12 @@ public function getPolicyFor($class)
669670
return $this->resolvePolicy($this->policies[$class]);
670671
}
671672

673+
$policy = $this->getPolicyFromAttribute($class);
674+
675+
if (! is_null($policy)) {
676+
return $this->resolvePolicy($policy);
677+
}
678+
672679
foreach ($this->guessPolicyName($class) as $guessedPolicy) {
673680
if (class_exists($guessedPolicy)) {
674681
return $this->resolvePolicy($guessedPolicy);
@@ -682,6 +689,25 @@ public function getPolicyFor($class)
682689
}
683690
}
684691

692+
/**
693+
* Get the policy class from the class attribute.
694+
*
695+
* @param class-string<*> $class
696+
* @return class-string<*>|null
697+
*/
698+
protected function getPolicyFromAttribute(string $class): ?string
699+
{
700+
if (! class_exists($class)) {
701+
return null;
702+
}
703+
704+
$attributes = (new ReflectionClass($class))->getAttributes(UsePolicy::class);
705+
706+
return $attributes !== []
707+
? $attributes[0]->newInstance()->class
708+
: null;
709+
}
710+
685711
/**
686712
* Guess the policy name for the given class.
687713
*
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Illuminate\Database\Eloquent\Attributes;
4+
5+
use Attribute;
6+
7+
#[Attribute(Attribute::TARGET_CLASS)]
8+
class UsePolicy
9+
{
10+
/**
11+
* Create a new attribute instance.
12+
*
13+
* @param class-string<*> $class
14+
*/
15+
public function __construct(public string $class)
16+
{
17+
}
18+
}

tests/Integration/Auth/GatePolicyResolutionTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Illuminate\Tests\Integration\Auth;
44

55
use Illuminate\Auth\Access\Events\GateEvaluated;
6+
use Illuminate\Database\Eloquent\Attributes\UsePolicy;
7+
use Illuminate\Database\Eloquent\Model;
68
use Illuminate\Support\Facades\Event;
79
use Illuminate\Support\Facades\Gate;
810
use Illuminate\Tests\Integration\Auth\Fixtures\AuthenticationTestUser;
@@ -78,4 +80,20 @@ public function testPolicyCanBeGuessedMultipleTimes()
7880
Gate::getPolicyFor(AuthenticationTestUser::class)
7981
);
8082
}
83+
84+
public function testPolicyCanBeGivenByAttribute(): void
85+
{
86+
Gate::guessPolicyNamesUsing(fn () => [AuthenticationTestUserPolicy::class]);
87+
88+
$this->assertInstanceOf(PostPolicy::class, Gate::getPolicyFor(Post::class));
89+
}
90+
}
91+
92+
#[UsePolicy(PostPolicy::class)]
93+
class Post extends Model
94+
{
95+
}
96+
97+
class PostPolicy
98+
{
8199
}

0 commit comments

Comments
 (0)