From 983d14bed871288abdb09442419e10cc8728ba2c Mon Sep 17 00:00:00 2001 From: SimonBroekaert Date: Thu, 30 Jan 2025 01:24:50 +0100 Subject: [PATCH 1/3] Introduces UsePolicy attribute --- .../Auth/Access/Attributes/UsePolicy.php | 17 +++++++++ src/Illuminate/Auth/Access/Gate.php | 36 +++++++++++++++++-- tests/Auth/AuthAccessGateTest.php | 19 ++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/Illuminate/Auth/Access/Attributes/UsePolicy.php diff --git a/src/Illuminate/Auth/Access/Attributes/UsePolicy.php b/src/Illuminate/Auth/Access/Attributes/UsePolicy.php new file mode 100644 index 000000000000..6c8e28ce9747 --- /dev/null +++ b/src/Illuminate/Auth/Access/Attributes/UsePolicy.php @@ -0,0 +1,17 @@ +resolvePolicy($this->policies[$class]); } + if ($policy = $this->tryResolvePolicyViaUsePolicyAttribute($class)) { + return $policy; + } + foreach ($this->guessPolicyName($class) as $guessedPolicy) { if (class_exists($guessedPolicy)) { return $this->resolvePolicy($guessedPolicy); @@ -708,6 +714,32 @@ protected function guessPolicyName($class) }) ?: [$classDirname.'\\Policies\\'.class_basename($class).'Policy']); } + /** + * Try to resolve the policy via the UsePolicy attribute. + * + * @param class-string $class + * @return mixed + */ + protected function tryResolvePolicyViaUsePolicyAttribute($class) + { + try { + $attributes = (new \ReflectionClass($class)) + ->getAttributes(UsePolicy::class); + } catch (Exception) { + return null; + } + + if ($attributes !== []) { + $usePolicy = $attributes[0]->newInstance(); + + $policy = new $usePolicy->policyClass; + + return $policy; + } + + return null; + } + /** * Specify a callback to be used to guess policy names. * diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 128ac8daca8e..c03bf532a5a7 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Auth; +use Illuminate\Auth\Access\Attributes\UsePolicy; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\Access\Gate; use Illuminate\Auth\Access\HandlesAuthorization; @@ -612,6 +613,18 @@ public function testForUserMethodAttachesANewUserToANewGateInstance() $this->assertTrue($gate->forUser((object) ['id' => 2])->check('foo')); } + public function testForUserMethodAttachesANewUserToANewGateInstanceWithTryResolvePolicyViaUsePolicyAttributeCallback() + { + $gate = $this->getBasicGate(); + + $policy = $gate->getPolicyFor(AccessGateTestDummyWithUsePolicyAttribute::class); + + $this->assertTrue( + $policy instanceof AccessGateTestPolicy && + get_class($policy) === AccessGateTestPolicy::class + ); + } + public function testForUserMethodAttachesANewUserToANewGateInstanceWithGuessCallback() { $gate = $this->getBasicGate(); @@ -1342,6 +1355,12 @@ class AccessGateTestDummy implements AccessGateTestDummyInterface // } +#[UsePolicy(AccessGateTestPolicy::class)] +class AccessGateTestDummyWithUsePolicyAttribute implements AccessGateTestDummyInterface +{ + // +} + class AccessGateTestSubDummy extends AccessGateTestDummy { // From e2c307cfded74e419c3015f8c38b90583c0e57e4 Mon Sep 17 00:00:00 2001 From: SimonBroekaert Date: Thu, 30 Jan 2025 07:33:50 +0100 Subject: [PATCH 2/3] Fix formatting to pass styleci check --- src/Illuminate/Auth/Access/Attributes/UsePolicy.php | 4 +++- src/Illuminate/Auth/Access/Gate.php | 5 ++--- tests/Auth/AuthAccessGateTest.php | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Auth/Access/Attributes/UsePolicy.php b/src/Illuminate/Auth/Access/Attributes/UsePolicy.php index 6c8e28ce9747..827617499254 100644 --- a/src/Illuminate/Auth/Access/Attributes/UsePolicy.php +++ b/src/Illuminate/Auth/Access/Attributes/UsePolicy.php @@ -13,5 +13,7 @@ class UsePolicy * @param class-string $policyClass * @return void */ - public function __construct(public string $policyClass) {} + public function __construct(public string $policyClass) + { + } } diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 959f1bfe6f4f..610dd7efcaab 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -4,8 +4,6 @@ use Closure; use Exception; -use function Illuminate\Support\enum_value; - use Illuminate\Auth\Access\Attributes\UsePolicy; use Illuminate\Auth\Access\Events\GateEvaluated; use Illuminate\Contracts\Auth\Access\Gate as GateContract; @@ -16,9 +14,10 @@ use Illuminate\Support\Str; use InvalidArgumentException; use ReflectionClass; - use ReflectionFunction; +use function Illuminate\Support\enum_value; + class Gate implements GateContract { use HandlesAuthorization; diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index c03bf532a5a7..b338b5f116d7 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -620,7 +620,7 @@ public function testForUserMethodAttachesANewUserToANewGateInstanceWithTryResolv $policy = $gate->getPolicyFor(AccessGateTestDummyWithUsePolicyAttribute::class); $this->assertTrue( - $policy instanceof AccessGateTestPolicy && + $policy instanceof AccessGateTestPolicy && get_class($policy) === AccessGateTestPolicy::class ); } From d199d3ecb0c4bffcecd5f09c441d7f6cd44c8537 Mon Sep 17 00:00:00 2001 From: Simon Broekaert Date: Thu, 30 Jan 2025 08:20:31 +0100 Subject: [PATCH 3/3] Resolve policy via the container Co-authored-by: Jeffrey Angenent <1571879+devfrey@users.noreply.github.com> --- src/Illuminate/Auth/Access/Gate.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 610dd7efcaab..6134795048c8 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -731,9 +731,7 @@ protected function tryResolvePolicyViaUsePolicyAttribute($class) if ($attributes !== []) { $usePolicy = $attributes[0]->newInstance(); - $policy = new $usePolicy->policyClass; - - return $policy; + return $this->resolvePolicy($usePolicy->policyClass); } return null;