Skip to content

Commit d19db37

Browse files
authored
fix Call to undefined method exception (#5)
* fix Call to undefined method exception when calling policy methods that don't exist
1 parent 9584723 commit d19db37

File tree

2 files changed

+42
-21
lines changed

2 files changed

+42
-21
lines changed

src/LaravelPolicySoftCache.php

+24-21
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ public static function flushCache(): void
2222
app()->make(static::class)->cache = [];
2323
}
2424

25-
/**
26-
* @param mixed $user
27-
* @param string $ability
28-
* @param mixed $args
29-
* @return mixed
30-
*/
3125
public function handleGateCall(mixed $user, string $ability, mixed $args): mixed
3226
{
3327
if (! is_array($args)) {
@@ -42,28 +36,41 @@ public function handleGateCall(mixed $user, string $ability, mixed $args): mixed
4236

4337
$policy = Gate::getPolicyFor($model);
4438

45-
if ($model && $this->shouldCache($policy)) {
39+
if ($model && $this->shouldCache($policy, $ability)) {
4640
return $this->callPolicyMethod($user, $policy, $ability, $args);
4741
}
4842

4943
return null;
5044
}
5145

52-
/**
53-
* @param object|null $policy
54-
* @return bool
55-
*/
56-
protected function shouldCache(?object $policy): bool
46+
protected function shouldCache(?object $policy, string $ability): bool
5747
{
58-
return $policy && ($policy instanceof SoftCacheable || config('policy-soft-cache.cache_all_policies', false) === true);
48+
// when policy is not filled don't cache it
49+
if (blank($policy)) {
50+
return false;
51+
}
52+
53+
// when policy is not an object don't cache it
54+
if (! is_object($policy)) {
55+
return false;
56+
}
57+
58+
// when policy doesn't have the ability don't cache it
59+
if (! method_exists($policy, $ability)) {
60+
return false;
61+
}
62+
63+
// when policy is soft cacheable cache it
64+
if ($policy instanceof SoftCacheable) {
65+
return true;
66+
}
67+
68+
// when config is set to cache all policies cache it
69+
return config('policy-soft-cache.cache_all_policies', false) === true;
5970
}
6071

6172
/**
62-
* @param Model $user
63-
* @param object $policy
64-
* @param string $ability
6573
* @param array<int,mixed> $args
66-
* @return mixed
6774
*/
6875
protected function callPolicyMethod(Model $user, object $policy, string $ability, array $args): mixed
6976
{
@@ -80,11 +87,7 @@ protected function callPolicyMethod(Model $user, object $policy, string $ability
8087
}
8188

8289
/**
83-
* @param Model $user
84-
* @param object $policy
8590
* @param array<int,mixed> $args
86-
* @param string $ability
87-
* @return string
8891
*/
8992
protected function getCacheKey(Model $user, object $policy, array $args, string $ability): string
9093
{

tests/PolicySoftCacheTest.php

+18
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@
2323
Config::set('policy-soft-cache.cache_all_policies', true);
2424
});
2525

26+
it('does not cache policy calls when ability does not exist', function () {
27+
Config::set('policy-soft-cache.cache_all_policies', false);
28+
29+
$user = new User();
30+
$testModel = new TestModel();
31+
$testModel->setAttribute('id', 1);
32+
33+
Gate::policy(TestModel::class, PolicyWithSoftCache::class);
34+
35+
$user->can('foo', $testModel);
36+
$user->can('foo', $testModel);
37+
38+
expect(PolicyWithSoftCache::$called)->toBe(0);
39+
40+
PolicyWithSoftCache::$called = 0;
41+
Config::set('policy-soft-cache.cache_all_policies', true);
42+
});
43+
2644
it('does not cache policy calls without SoftCacheable interface', function () {
2745
Config::set('policy-soft-cache.cache_all_policies', false);
2846

0 commit comments

Comments
 (0)