目录
1、简介
1.1 安装&配置
2、订阅实现
2.1 创建订阅
2.2 检查订阅状态
2.3 修改订阅
2.4 订阅数量
2.5 订阅税金
2.6 取消订阅
2.7 恢复订阅
3、处理 StripeWebhook
3.1 订阅失败处理
3.2 其它Webhooks
4、一次性付款
5、发票
生成PDF发票
首页 后端开发 php教程 [ Laravel 5.2 文档 ] 服务 -- 订阅支付实现:Laravel Cashier

[ Laravel 5.2 文档 ] 服务 -- 订阅支付实现:Laravel Cashier

Jun 20, 2016 pm 12:38 PM

1、简介

LaravelCashier 为通过  Stripe实现订阅支付服务提供了一个优雅平滑的接口。它封装了几乎所有你恐惧编写的样板化的订阅支付代码。除了基本的订阅管理外,Cashier还支持处理优惠券、订阅升级/替换、订阅“数量”、取消宽限期,甚至生成PDF 发票。

1.1 安装&配置

Composer

首先,添加 Cashier 包到 composer.json文件并运行 composer update命令:

"laravel/cashier": "~6.0"
登录后复制

服务提供者

接下来,在 config/app.php配置文件中注册服务提供者: Laravel\Cashier\CashierServiceProvider。

迁移

使用 Cashier 之前,我们需要准备好数据库。我们需要添加一个字段到 users表,还要创建新的 subscriptions表来处理所有用户订阅:

Schema::table('users', function ($table) {    $table->string('stripe_id')->nullable();    $table->string('card_brand')->nullable();    $table->string('card_last_four')->nullable();});Schema::create('subscriptions', function ($table) {    $table->increments('id');    $table->integer('user_id');    $table->string('name');    $table->string('stripe_id');    $table->string('stripe_plan');    $table->integer('quantity');    $table->timestamp('trial_ends_at')->nullable();    $table->timestamp('ends_at')->nullable();    $table->timestamps();});
登录后复制

创建好迁移后,只需简单运行 migrate命令,相应修改就会更新到数据库。

设置模型

接下来,添加 Billabletrait 到 User模型类:

use Laravel\Cashier\Billable;class User extends Authenticatable{    use Billable;}
登录后复制

Stripe键

最后,在配置文件 config/services.php中设置 Stripe 键:

'stripe' => [    'model'  => 'User',    'secret' => env('STRIPE_API_SECRET'),],
登录后复制

2、订阅实现

2.1 创建订阅

要创建一个订阅,首先要获取一个账单模型的实例,通常是 App\User的实例。获取到该模型实例之后,你可以使用 newSubscription方法来创建该模型的订阅:

$user = User::find(1);$user->newSubscription('main', 'monthly')->create($creditCardToken);
登录后复制

第一个传递给 newSubscription方法的参数是该订阅的名字,如果应用只有一个订阅,可以将其称作 main或 primary,第二个参数用于指定用户订阅的 Stripe计划,该值对应 Stripe 中相应计划的 id。

create方法会自动创建这个 Stripe 订阅,同时更新数据库中 Stripe 的客户 ID(即 users表中的 stripe_id)和其它相关的账单信息。如果你的订阅计划有试用期,试用期结束时间也会自动被设置到数据库相应字段。

额外的用户信息

如果你想要指定额外的客户信息,你可以将其作为第二个参数传递给 create方法:

$user->newSubscription('main', 'monthly')->create($creditCardToken, [    'email' => $email,     'description' => 'Our First Customer']);
登录后复制

要了解更多 Stripe 支持的字段,可以查看 Stripe 关于 创建消费者的文档。

优惠券

如果你想要在创建订阅的时候使用优惠券,可以使用 withCoupon方法:

$user->newSubscription('main', 'monthly')     ->withCoupon('code')     ->create($creditCardToken);
登录后复制

2.2 检查订阅状态

用户订阅你的应用后,你可以使用各种便利的方法来简单检查订阅状态。首先,如果用户有一个有效的订阅,则 subscribed方法返回 true,即使订阅现在出于试用期:

if ($user->subscribed('main')) {    //}
登录后复制

subscribed方法还可以用于路由中间件,基于用户订阅状态允许你对路由和控制器的访问进行过滤:

public function handle($request, Closure $next){    if ($request->user() && ! $request->user()->subscribed('main')) {        // This user is not a paying customer...        return redirect('billing');    }    return $next($request);}
登录后复制

如果你想要判断一个用户是否还在试用期,可以使用 onTrial方法,该方法在为还处于试用期的用户显示警告信息很有用:

if ($user->->subscription('main')->onTrial()) {    //}
登录后复制

onPlan方法可用于判断用户是否基于 Stripe ID 订阅了给定的计划:

if ($user->onPlan('monthly')) {    //}
登录后复制

已取消的订阅状态

要判断用户是否曾经是有效的订阅者,但现在取消了订阅,可以使用 cancelled方法:

if ($user->subscription('main')->cancelled()) {    //}
登录后复制

你还可以判断用户是否曾经取消过订阅,但现在仍然在“宽限期”直到完全失效。例如,如果一个用户在3月5号取消了一个实际有效期到3月10号的订阅,该用户处于“宽限期”直到3月10号。注意 subscribed方法在此期间仍然返回 true。

if ($user->subscription('main')->onGracePeriod()) {    //}
登录后复制
登录后复制

2.3 修改订阅

用户订阅应用后,偶尔想要改变到新的订阅计划,要将用户切换到新的订阅,使用 swap方法。例如,我们可以轻松切换用户到 premium订阅:

$user = App\User::find(1);$user->subscription('main')->swap('stripe-plan-id');
登录后复制

如果用户在试用,试用期将会被维护。还有,如果订阅存在数量,数量也可以被维护。切换订阅计划后,

可以使用 invoice方法立即给用户开发票:

$user->subscription('main')->swap('stripe-plan-id');$user->invoice();
登录后复制

2.4 订阅数量

有时候订阅也会被数量影响,例如,应用中每个账户每月需要付费$10,要简单增加或减少订阅数量,使用 incrementQuantity和 decrementQuantity方法:

$user = User::find(1);$user->subscription('main')->incrementQuantity();// Add five to the subscription's current quantity...$user->subscription('main')->incrementQuantity(5);$user->subscription('main')->decrementQuantity();// Subtract five to the subscription's current quantity...$user->subscription('main')->decrementQuantity(5);
登录后复制

你也可以使用 updateQuantity方法指定数量:

$user->subscription('main')->updateQuantity(10);
登录后复制

想要了解更多订阅数量信息,查阅相关 Stripe文档。

2.5 订阅税金

在 Cashier 中,提供 tax_percent值发送给 Stripe 很简单。要指定用户支付订阅的税率,实现账单模型的 getTaxPercent方法,并返回一个在0到100之间的数值,不要超过两位小数:

public function getTaxPercent() {    return 20;}
登录后复制

这将使你可以在模型基础上使用税率,对跨越不同国家的用户很有用。

2.6 取消订阅

要取消订阅,可以调用用户订阅上的 cancel方法:

$user->subscription('main')->cancel();
登录后复制

当订阅被取消时,Cashier 将会自动设置数据库中的 subscription_ends_at字段。该字段用于了解 subscribed方法什么时候开始返回 false。例如,如果客户3月1号份取消订阅,但订阅直到3月5号才会结束,那么 subscribed方法继续返回 true直到3月5号。

你可以使用 onGracePeriod方法判断用户是否已经取消订阅但仍然在“宽限期”:

if ($user->subscription('main')->onGracePeriod()) {    //}
登录后复制
登录后复制

2.7 恢复订阅

如果用户已经取消订阅但想要恢复该订阅,可以使用 resume方法,前提是该用户必须在宽限期内:

$user->subscription('main')->resume();
登录后复制

如果该用户取消了一个订阅然后在订阅失效之前恢复了这个订阅,则不会立即支付该账单,取而代之的,他们的订阅只是被重新激活,并回到正常的支付周期。

3、处理 StripeWebhook

3.1 订阅失败处理

如果客户的信用卡失效怎么办?不用担心—— Cashier 自带了 Webhook 控制器,该控制器可以很方便地为你取消客户订阅。只需要定义如下控制器路由:

Route::post('stripe/webhook', 'Laravel\Cashier\WebhookController@handleWebhook');
登录后复制

就是这样!失败的支付将会被该控制器捕获和处理。当 Stripe 判断订阅失败(正常情况下尝试支付失败三次后)时该控制器将会取消客户的订阅。不要忘了:你需要在 Stripe 控制面板设置中配置相应的 webhook URI,否则不能正常工作。

由于 Stripe webhooks 需要通过 Laravel 的CSRF验证,所以我们将该 URI 置于 VerifyCsrfToken中间件排除列表中:

protected $except = [    'stripe/*',];
登录后复制

3.2 其它Webhooks

如果你有额外想要处理的 Stripe webhook 事件,只需简单继承 Webhook 控制器, 你的方法名应该和 Cashier 期望的约定一致,尤其是方法应该以“handle”开头并以驼峰命名法命名。例如,如果你想要处理 invoice.payment_succeededwebhook,你应该添加 handleInvoicePaymentSucceeded方法到控制器:

<?phpnamespace App\Http\Controller;use Laravel\Cashier\WebhookController as BaseController;class WebhookController extends BaseController{    /**     * 处理 stripe webhook.     *     * @param  array  $payload     * @return Response     */    public function handleInvoicePaymentSucceeded($payload)    {        // 处理该事件    }}
登录后复制

4、一次性付款

如果你想要使用订阅客户的信用卡一次性结清账单,可以使用账单模型实例上的 charge方法,该方法接收付款金额(应用使用的货币的最小单位对应的金额数值)作为参数,例如,下面的例子使用信用卡支付100美分,或1美元:

$user->charge(100);
登录后复制

charge方法接收一个数组作为第二个参数,允许你传递任何你想要传递的底层 Stripe 账单创建参数:

$user->charge(100, [    'source' => $token,    'receipt_email' => $user->email,]);
登录后复制

如果支付失败 charge方法将返回 false,这通常表明付款被拒绝:

if ( ! $user->charge(100)) {    // The charge was denied...}
登录后复制

如果支付成功,该方法将会返回一个完整的 Stripe 响应。

5、发票

你可以使用 invoices方法轻松获取账单模型的发票数组:

$invoices = $user->invoices();
登录后复制

当列出客户发票时,你可以使用发票的辅助函数来显示相关的发票信息。例如,你可能想要在表格中列出每张发票,从而方便用户下载它们:

<table>    @foreach ($invoices as $invoice)        <tr>            <td>{{ $invoice->dateString() }}</td>            <td>{{ $invoice->dollars() }}</td>            <td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>        </tr>    @endforeach</table>
登录后复制

生成PDF发票

在生成PDF分票之前,需要安装 PHP 库 dompdf:

composer require dompdf/dompdf
登录后复制

在路由或控制器中,使用 downloadInvoice方法生成发票的 PDF 下载,该方法将会自动生成相应的 HTTP 响应发送下载到浏览器:

Route::get('user/invoice/{invoice}', function ($invoiceId) {    return Auth::user()->downloadInvoice($invoiceId, [        'vendor'  => 'Your Company',        'product' => 'Your Product',    ]);});
登录后复制
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

PHP 8.1中的枚举(枚举)是什么? PHP 8.1中的枚举(枚举)是什么? Apr 03, 2025 am 12:05 AM

PHP8.1中的枚举功能通过定义命名常量增强了代码的清晰度和类型安全性。1)枚举可以是整数、字符串或对象,提高了代码可读性和类型安全性。2)枚举基于类,支持面向对象特性,如遍历和反射。3)枚举可用于比较和赋值,确保类型安全。4)枚举支持添加方法,实现复杂逻辑。5)严格类型检查和错误处理可避免常见错误。6)枚举减少魔法值,提升可维护性,但需注意性能优化。

会话如何劫持工作,如何在PHP中减轻它? 会话如何劫持工作,如何在PHP中减轻它? Apr 06, 2025 am 12:02 AM

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

描述扎实的原则及其如何应用于PHP的开发。 描述扎实的原则及其如何应用于PHP的开发。 Apr 03, 2025 am 12:04 AM

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

解释PHP中的晚期静态绑定(静态::)。 解释PHP中的晚期静态绑定(静态::)。 Apr 03, 2025 am 12:04 AM

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。

什么是REST API设计原理? 什么是REST API设计原理? Apr 04, 2025 am 12:01 AM

RESTAPI设计原则包括资源定义、URI设计、HTTP方法使用、状态码使用、版本控制和HATEOAS。1.资源应使用名词表示并保持层次结构。2.HTTP方法应符合其语义,如GET用于获取资源。3.状态码应正确使用,如404表示资源不存在。4.版本控制可通过URI或头部实现。5.HATEOAS通过响应中的链接引导客户端操作。

您如何在PHP中有效处理异常(尝试,捕捉,最后,投掷)? 您如何在PHP中有效处理异常(尝试,捕捉,最后,投掷)? Apr 05, 2025 am 12:03 AM

在PHP中,异常处理通过try,catch,finally,和throw关键字实现。1)try块包围可能抛出异常的代码;2)catch块处理异常;3)finally块确保代码始终执行;4)throw用于手动抛出异常。这些机制帮助提升代码的健壮性和可维护性。

PHP中的匿名类是什么?您何时可以使用它们? PHP中的匿名类是什么?您何时可以使用它们? Apr 04, 2025 am 12:02 AM

匿名类在PHP中的主要作用是创建一次性使用的对象。1.匿名类允许在代码中直接定义没有名字的类,适用于临时需求。2.它们可以继承类或实现接口,增加灵活性。3.使用时需注意性能和代码可读性,避免重复定义相同的匿名类。

See all articles