Skip to content

Commit 02c5dc5

Browse files
cbltaylorotwell
andauthored
[8.x] Add gate policy callback (#39185)
* wip * wip * Apply fixes from StyleCI * formatting * wip * Apply fixes from StyleCI Co-authored-by: Taylor Otwell <taylorotwell@gmail.com>
1 parent a01e9ed commit 02c5dc5

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

src/Illuminate/Auth/Access/Gate.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ public function denies($ability, $arguments = [])
279279
*/
280280
public function check($abilities, $arguments = [])
281281
{
282+
if (is_array($abilities) && class_exists($abilities[0])) {
283+
$abilities = [$abilities];
284+
}
285+
282286
return collect($abilities)->every(function ($ability) use ($arguments) {
283287
return $this->inspect($ability, $arguments)->allowed();
284288
});
@@ -293,6 +297,13 @@ public function check($abilities, $arguments = [])
293297
*/
294298
public function any($abilities, $arguments = [])
295299
{
300+
// Gate::any([Policy::class, ['view', 'create']], $post)...
301+
if (isset($abilities[1]) && is_array($abilities[1])) {
302+
$abilities = collect($abilities[1])->map(function ($ability) use ($abilities) {
303+
return [$abilities[0], $ability];
304+
})->all();
305+
}
306+
296307
return collect($abilities)->contains(function ($ability) use ($arguments) {
297308
return $this->check($ability, $arguments);
298309
});
@@ -556,6 +567,19 @@ protected function resolveAuthCallback($user, $ability, array $arguments)
556567
return $callback;
557568
}
558569

570+
if (is_array($ability)) {
571+
[$class, $method] = $ability;
572+
573+
if ($this->canBeCalledWithUser($user, $class, $method)) {
574+
return $this->getCallableFromClassAndMethod($class, $method);
575+
}
576+
}
577+
578+
if (class_exists($ability) &&
579+
$this->canBeCalledWithUser($user, $ability, '__invoke')) {
580+
return $this->getCallableFromClassAndMethod($ability);
581+
}
582+
559583
if (isset($this->stringCallbacks[$ability])) {
560584
[$class, $method] = Str::parseCallback($this->stringCallbacks[$ability]);
561585

@@ -781,6 +805,20 @@ protected function resolveUser()
781805
return call_user_func($this->userResolver);
782806
}
783807

808+
/**
809+
* Get a callable from a class and method.
810+
*
811+
* @param string $class
812+
* @param string $method
813+
* @return \Closure
814+
*/
815+
protected function getCallableFromClassAndMethod($class, $method = '__invoke')
816+
{
817+
return function (...$params) use ($class, $method) {
818+
return $this->container->make($class)->{$method}(...$params);
819+
};
820+
}
821+
784822
/**
785823
* Get all of the defined abilities.
786824
*

src/Illuminate/Foundation/Auth/Access/AuthorizesRequests.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ protected function parseAbilityAndArguments($ability, $arguments)
5353
return [$ability, $arguments];
5454
}
5555

56+
if (is_array($ability)) {
57+
return [$ability, $arguments];
58+
}
59+
5660
$method = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'];
5761

5862
return [$this->normalizeGuessedAbilityName($method), $ability];

tests/Auth/AuthAccessGateTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,46 @@ public function testEveryAbilityCheckFailsIfNonePass()
759759
$this->assertFalse($gate->check(['edit', 'update'], new AccessGateTestDummy));
760760
}
761761

762+
public function testInspectPolicyCallback()
763+
{
764+
$gate = $this->getBasicGate();
765+
766+
$response = $gate->inspect([AccessGateTestPolicyWithAllPermissions::class, 'edit'], new AccessGateTestDummy);
767+
768+
$this->assertFalse($response->denied());
769+
$this->assertTrue($response->allowed());
770+
}
771+
772+
public function testInspectPolicyCallbackInvoke()
773+
{
774+
$gate = $this->getBasicGate();
775+
776+
$response = $gate->inspect(AccessGateTestGuestInvokableClass::class, new AccessGateTestDummy);
777+
778+
$this->assertFalse($response->denied());
779+
$this->assertTrue($response->allowed());
780+
}
781+
782+
public function testCheckUsingPolicyCallback()
783+
{
784+
$gate = $this->getBasicGate();
785+
786+
$this->assertTrue($gate->check(
787+
[AccessGateTestPolicyWithAllPermissions::class, 'edit'],
788+
new AccessGateTestDummy)
789+
);
790+
}
791+
792+
public function testAnyUsingPolicyCallback()
793+
{
794+
$gate = $this->getBasicGate();
795+
796+
$this->assertTrue($gate->any(
797+
[AccessGateTestPolicyWithAllPermissions::class, ['edit', 'update']],
798+
new AccessGateTestDummy)
799+
);
800+
}
801+
762802
/**
763803
* @dataProvider hasAbilitiesTestDataProvider
764804
*

tests/Foundation/FoundationAuthorizesRequestsTraitTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ protected function tearDown(): void
1717
Container::setInstance(null);
1818
}
1919

20+
public function testCallableGateCheck()
21+
{
22+
unset($_SERVER['_test.authorizes.trait']);
23+
24+
$gate = $this->getBasicGate();
25+
26+
$response = (new FoundationTestAuthorizeTraitClass)->authorize([FoundationAuthorizesRequestTestPolicy::class, 'create']);
27+
28+
$this->assertInstanceOf(Response::class, $response);
29+
$this->assertTrue($_SERVER['_test.authorizes.trait.policy']);
30+
}
31+
2032
public function testBasicGateCheck()
2133
{
2234
unset($_SERVER['_test.authorizes.trait']);

0 commit comments

Comments
 (0)