From 783297694ca3c69563c8aa1f16fef64608290201 Mon Sep 17 00:00:00 2001 From: Ovidiu U Date: Wed, 29 Apr 2026 18:32:55 +0100 Subject: [PATCH] fix: model audit cleanups (primaryKey, fuel_type cast, cadence cache) - StationPriceCurrent: $primaryKey was null; set to 'station_id' + keyType string so Eloquent has a sensible default for save() / find() paths. - UserNotificationPreference: add FuelType enum cast on fuel_type so it hydrates as an enum like every other price model. - Plan::resolveCadenceForUser: cache for 1h under the same plans tag as resolveForUser; HandleStripeWebhook busts both keys on subscription events. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/Listeners/HandleStripeWebhook.php | 4 +- app/Models/Plan.php | 48 +++++++++++++---------- app/Models/StationPriceCurrent.php | 4 +- app/Models/UserNotificationPreference.php | 2 + 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/app/Listeners/HandleStripeWebhook.php b/app/Listeners/HandleStripeWebhook.php index 25b1de9..00ec40a 100644 --- a/app/Listeners/HandleStripeWebhook.php +++ b/app/Listeners/HandleStripeWebhook.php @@ -129,6 +129,8 @@ final class HandleStripeWebhook private function bustPlanCache(User $user): void { - Cache::tags(['plans'])->forget("plan_for_user_{$user->id}"); + $tag = Cache::tags(['plans']); + $tag->forget("plan_for_user_{$user->id}"); + $tag->forget("plan_cadence_for_user_{$user->id}"); } } diff --git a/app/Models/Plan.php b/app/Models/Plan.php index 4fe3fcf..e07147a 100644 --- a/app/Models/Plan.php +++ b/app/Models/Plan.php @@ -77,33 +77,41 @@ class Plan extends Model */ public static function resolveCadenceForUser(User $user): ?string { - if (! method_exists($user, 'subscriptions')) { - return null; - } + $cache = Cache::supportsTags() ? Cache::tags(['plans']) : Cache::store(); - $priceId = $user->subscriptions()->active()->value('stripe_price'); + return $cache->remember( + "plan_cadence_for_user_{$user->id}", + 3600, + function () use ($user): ?string { + if (! method_exists($user, 'subscriptions')) { + return null; + } - if ($priceId === null) { - return null; - } + $priceId = $user->subscriptions()->active()->value('stripe_price'); - $plan = static::where('stripe_price_id_monthly', $priceId) - ->orWhere('stripe_price_id_annual', $priceId) - ->first(); + if ($priceId === null) { + return null; + } - if ($plan === null) { - return null; - } + $plan = static::where('stripe_price_id_monthly', $priceId) + ->orWhere('stripe_price_id_annual', $priceId) + ->first(); - if ($plan->stripe_price_id_monthly === $priceId) { - return 'monthly'; - } + if ($plan === null) { + return null; + } - if ($plan->stripe_price_id_annual === $priceId) { - return 'annual'; - } + if ($plan->stripe_price_id_monthly === $priceId) { + return 'monthly'; + } - return null; + if ($plan->stripe_price_id_annual === $priceId) { + return 'annual'; + } + + return null; + } + ); } protected static function booted(): void diff --git a/app/Models/StationPriceCurrent.php b/app/Models/StationPriceCurrent.php index 39758be..050e865 100644 --- a/app/Models/StationPriceCurrent.php +++ b/app/Models/StationPriceCurrent.php @@ -19,7 +19,9 @@ class StationPriceCurrent extends Model public $timestamps = false; - protected $primaryKey = null; + protected $primaryKey = 'station_id'; + + protected $keyType = 'string'; public $incrementing = false; diff --git a/app/Models/UserNotificationPreference.php b/app/Models/UserNotificationPreference.php index 19cc990..b861493 100644 --- a/app/Models/UserNotificationPreference.php +++ b/app/Models/UserNotificationPreference.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Enums\FuelType; use Database\Factories\UserNotificationPreferenceFactory; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -44,6 +45,7 @@ class UserNotificationPreference extends Model { return [ 'enabled' => 'boolean', + 'fuel_type' => FuelType::class, ]; } }