Guard HandleStripeWebhook plan-cache bust against non-taggable cache stores

bustPlanCache() called Cache::tags() unconditionally, which throws on the
`database`/`file` cache drivers. Mirror the Cache::supportsTags() idiom used in
Plan.php so Stripe webhooks work regardless of the configured cache store.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ovidiu U
2026-06-11 10:56:48 +01:00
parent 257c09d178
commit 5a6967dc01
2 changed files with 22 additions and 3 deletions

View File

@@ -129,8 +129,9 @@ final class HandleStripeWebhook
private function bustPlanCache(User $user): void private function bustPlanCache(User $user): void
{ {
$tag = Cache::tags(['plans']); $cache = Cache::supportsTags() ? Cache::tags(['plans']) : Cache::store();
$tag->forget("plan_for_user_{$user->id}");
$tag->forget("plan_cadence_for_user_{$user->id}"); $cache->forget("plan_for_user_{$user->id}");
$cache->forget("plan_cadence_for_user_{$user->id}");
} }
} }

View File

@@ -24,6 +24,24 @@ it('busts the plan cache on customer.subscription.created', function (): void {
expect(Cache::tags(['plans'])->get("plan_for_user_{$user->id}"))->toBeNull(); expect(Cache::tags(['plans'])->get("plan_for_user_{$user->id}"))->toBeNull();
}); });
it('busts the plan cache without error on a cache store that does not support tags', function (): void {
// The `file` driver is not taggable — calling Cache::tags() on it throws.
// This guards against a regression where bustPlanCache assumed a taggable store.
config(['cache.default' => 'file']);
Cache::store('file')->flush();
expect(Cache::supportsTags())->toBeFalse();
$user = User::factory()->create(['stripe_id' => 'cus_notags_1']);
Cache::put("plan_for_user_{$user->id}", 'stale', 3600);
(new HandleStripeWebhook)->handle(new WebhookReceived([
'type' => 'customer.subscription.created',
'data' => ['object' => ['customer' => 'cus_notags_1']],
]));
expect(Cache::get("plan_for_user_{$user->id}"))->toBeNull();
});
it('ignores subscription.created when the user is not found', function (): void { it('ignores subscription.created when the user is not found', function (): void {
(new HandleStripeWebhook)->handle(new WebhookReceived([ (new HandleStripeWebhook)->handle(new WebhookReceived([
'type' => 'customer.subscription.created', 'type' => 'customer.subscription.created',