Laravel Cashier订阅名称不更新,如何保留subscribed()方法判断套餐?
解决Laravel Cashier订阅名称不同步,保留subscribed()方法判断套餐的方案
最优方案:通过Stripe Webhook同步订阅名称到Cashier表
Cashier的subscribed('tier2')方法依赖于subscriptions表的name字段判断套餐,而Stripe门户修改订阅时不会自动同步这个字段,我们可以通过监听Stripe的customer.subscription.updated事件主动更新该字段,这完全符合Cashier的设计逻辑,不存在“修改Cashier管理的表不妥当”的问题。
具体步骤:
- 确保已配置Stripe Webhook并启用
customer.subscription.updated事件监听 - 在Webhook处理逻辑中完成以下操作:
- 通过Stripe订阅ID找到对应的Cashier订阅记录
- 从Stripe返回的订阅数据中提取当前价格ID,再获取该价格关联的产品信息(产品名称或自定义套餐标识)
- 更新订阅记录的
name字段为套餐标识
代码示例:
// Webhook处理控制器中的方法 public function handleSubscriptionUpdated(array $payload) { $stripeSubscription = $payload['data']['object']; $subscription = \Laravel\Cashier\Subscription::findByStripeId($stripeSubscription['id']); if (!$subscription) { return; } // 获取当前订阅的价格ID $priceId = $stripeSubscription['items']['data'][0]['price']['id']; // 从Stripe获取价格对应的产品信息 $price = \Stripe\Price::retrieve($priceId); // 这里可以直接用产品名称,或者从产品metadata取自定义标识(更灵活) $planName = $price->product->name; // 若用metadata:$planName = $price->product->metadata['plan_slug']; $subscription->update(['name' => $planName]); }
完成后,subscribed('tier2')就能正常判断用户当前的订阅套餐,同时保留Stripe门户的订阅管理功能。
备选方案:扩展User模型的subscribed方法(无需修改数据库)
如果不想修改subscriptions表,可以通过扩展User模型的subscribed方法,实现价格ID到套餐名称的映射,同时保留原有方法的功能。
具体步骤:
- 在User模型中定义价格与套餐名称的映射数组
- 重写
subscribed方法,先调用父类逻辑,若未匹配则通过价格映射判断
代码示例:
// App\Models\User.php use Laravel\Cashier\Billable; class User extends Authenticatable { use Billable; // 定义Stripe价格ID到套餐名称的映射 protected $priceToPlan = [ 'price_xxxxxx' => 'tier1', 'price_yyyyyy' => 'tier2', // 新增套餐时补充映射关系 ]; public function subscribed($plan = null, $subscription = 'default') { // 处理传入价格ID的情况,映射为套餐名称 if ($plan && isset($this->priceToPlan[$plan])) { $plan = $this->priceToPlan[$plan]; } // 先执行父类的subscribed逻辑 $parentCheck = parent::subscribed($plan, $subscription); if ($parentCheck) { return true; } // 父类未匹配时,通过当前订阅的priceID判断 $subscriptionInstance = $this->subscription($subscription); if (!$subscriptionInstance || !$subscriptionInstance->valid()) { return false; } return isset($this->priceToPlan[$subscriptionInstance->stripe_price]) && $this->priceToPlan[$subscriptionInstance->stripe_price] === $plan; } }
这种方式无需修改数据库,原有的subscribed('tier2')调用逻辑完全不变,同时兼容通过价格ID判断的场景。
内容的提问来源于stack exchange,提问作者scopic
相关产品推荐
相关产品推荐

