* * * * *
[TOC]
## 簡介
Laravel Cashier 提供了直觀、流暢的接口來接入?[Stripe's](https://stripe.com/)?和?[Braintree's](https://www.braintreepayments.com/)?訂閱付費服務。它可以處理幾乎所有你寫起來非常頭疼付費訂閱代碼。除了提供基本的訂閱管理之外,Cashier 還可以幫你處理優惠券,交換訂閱、訂閱“數量”、取消寬限期,甚至還可以生成pdf文檔。
> {note} 如果你只是“一次性”的收費并且不提供訂閱。你就不應該使用 Cashier 。可以直接使用 Stripe 和 Braintree 的 sdk。
## 配置
### Stripe
#### Composer
首先, 將 Stripe 的 Cashier 包添加到你的依賴項中:
~~~
composer require "laravel/cashier":"~7.0"
~~~
#### 數據庫遷移
在使用 Cashier 之前,我們需要?[準備數據庫](http://www.hmoore.net/tonyyu/laravel_5_6/786263)。. 我們需要向你的?`users`?表中添加幾個列,并創建一個新的?`subscriptions`?表來保存所有客戶的訂閱:
~~~
Schema::table('users', function ($table) {
$table->string('stripe_id')->nullable();
$table->string('card_brand')->nullable();
$table->string('card_last_four')->nullable();
$table->timestamp('trial_ends_at')->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();
});
~~~
一旦遷移文件建立好后,運行 Artisan 的?`migrate`?命令。
#### Billable 模型
接下來,添加?`Billable`?trait 到模型定義,這個 trait 提供了多個方法以便執行常用支付任務,例如創建訂閱、使用優惠券以及更新信用卡信息:
~~~
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}
~~~
#### API Keys
最后,在配置文件?`services.php`?中配置 Stripe 的 key,你可以在Stripe 官網個人中心的控制面板中獲取這些 Stripe API key 信息:
~~~
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
~~~
### Braintree
#### Braintree 注意事項
對于很多操作,Stripe 和 Braintree 實現的 Cashier 功能都是一樣的,兩者都提供了通過信用卡進行訂閱支付的功能,但是 Braintree 還支持通過 PayPal 支付。不過,Braintree 也缺失一些 Stripe 支持的功能,在決定使用 Stripe 還是 Braintree 之前,需要考慮以下幾點:
* Braintree 支持 PayPal 而 Stripe 不支持;
* Braintree 不支持?`increment`?和?`decrement`?方法,這是 Braintree 的限制,而不是 Cashier 限制。
* Braintree 不支持基于百分比的折扣。這是 Braintree 的限制,而不是 Cashier 限制。
#### Composer
首先,將 Braintree 的 Cashier 包添加到你的依賴項:
~~~
composer require "laravel/cashier-braintree":"~2.0"
~~~
#### Service Provider
接下來, 在?`config/app.php`?配置文件中,注冊 Laravel\Cashier\CashierServiceProvider?[服務提供者](http://www.hmoore.net/tonyyu/laravel_5_6/786057):
~~~
Laravel\Cashier\CashierServiceProvider::class
~~~
#### 信用卡優惠計劃
在使用 Cashier 之前,你需要首先在 Braintree 控制面板定義一個?`plan-credit`?折扣。這個折扣會根據用戶選擇的支付選項匹配合適的折扣比例,比如選擇年付還是月付。
在 Braintree 控制面板中配置的折扣總額可以隨意填,Cashier 會在每次使用優惠券的時候根據我們自己的定制覆蓋該默認值。由于 Braintree 不支持在訂閱頻率上來匹配折扣比例,所以這一優惠券是必需的。
#### 數據庫遷移
開始使用 Cashier 之前, 我們需要?[準備一下數據庫](http://www.hmoore.net/tonyyu/laravel_5_6/786263)。我們需要在數據庫的?`users`?表中新增幾列,以及創建一個新的?`subscriptions`?表來存儲客戶的訂閱信息:
~~~
Schema::table('users', function ($table) {
$table->string('braintree_id')->nullable();
$table->string('paypal_email')->nullable();
$table->string('card_brand')->nullable();
$table->string('card_last_four')->nullable();
$table->timestamp('trial_ends_at')->nullable();
});
Schema::create('subscriptions', function ($table) {
$table->increments('id');
$table->integer('user_id');
$table->string('name');
$table->string('braintree_id');
$table->string('braintree_plan');
$table->integer('quantity');
$table->timestamp('trial_ends_at')->nullable();
$table->timestamp('ends_at')->nullable();
$table->timestamps();
});
~~~
一旦遷移文件建立好后,運行 Artisan 的?`migrate`?命令。
#### Billable 模型
下一步, 添加?`Billable`?trait 到你的模型定義 :
~~~
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}
~~~
#### API Keys
下一步, 你應該在?`services.php`?文件中,參考下面的配置選項:
~~~
'braintree' => [
'model' => App\User::class,
'environment' => env('BRAINTREE_ENV'),
'merchant_id' => env('BRAINTREE_MERCHANT_ID'),
'public_key' => env('BRAINTREE_PUBLIC_KEY'),
'private_key' => env('BRAINTREE_PRIVATE_KEY'),
],
~~~
然后,你應該向?`AppServiceProvider`?服務提供商的?`boot`?方法中,添加以下的 Braintree SDK 調用:
~~~
\Braintree_Configuration::environment(config('services.braintree.environment'));
\Braintree_Configuration::merchantId(config('services.braintree.merchant_id'));
\Braintree_Configuration::publicKey(config('services.braintree.public_key'));
\Braintree_Configuration::privateKey(config('services.braintree.private_key'));
~~~
### 貨幣配置
Cashier 使用美元(USD)作為默認貨幣。你可以通過在服務提供者的?`boot`?方法中調用?`Cashier::useCurrency`?方法來更改默認的貨幣。這個?`useCurrency`?方法接受兩個字符串參數:貨幣和貨幣符號:
~~~
use Laravel\Cashier\Cashier;
Cashier::useCurrency('eur', '€');
~~~
## 訂閱
### 創建訂閱
創建訂閱,首先需要獲取到一個 Billable 模型實例,這通常是?`App\User`?的一個實例。一旦你獲取了模型實例,你可以使用?`newSubscription`?方法創建模型的訂閱:
~~~
$user = User::find(1);
$user->newSubscription('main', 'premium')->create($stripeToken);
~~~
`newSubscription`?方法的第一個參數應該是訂閱的名稱。如果你的應用程序只提供一個訂閱,那么你可以將其設置為?`main`?或者?`primary`。
第二個參數是用戶訂閱的 Stripe / Braintree 計劃。這個值應該與 Stripe 或 Braintree 中的標識符對應。
`create`?方法接受一個 Stripe 信用卡 / 源令牌,它將開始訂閱,并使用客戶 ID 和其他相關的賬單信息更新數據庫。
#### 用戶其他的詳細信息
如果你想要指定用戶其他的詳細信息,你可以通過將它們作為第二個參數傳遞給?`create`?方法:
~~~
$user->newSubscription('main', 'monthly')->create($stripeToken, [
'email' => $email,
]);
~~~
要了解更多關于 Stripe 或 Braintree 支持的額外字段,請查看 Stripe 的[內容創建客戶文檔](https://stripe.com/docs/api#create_customer)?或對應的?[Braintree 文檔](https://developers.braintreepayments.com/reference/request/customer/create/php)。
#### 優惠券
如果你想在創建訂閱時使用優惠券,你可以使用?`withCoupon`?方法:
~~~
$user->newSubscription('main', 'monthly')
->withCoupon('code')
->create($stripeToken);
~~~
### 檢查訂閱狀態
一旦用戶在你的應用程序訂閱了,你可以使用各種方便的方法輕松地檢查他們的訂閱狀態。首先,如果用戶有一個激活的訂閱,那么?`subscribed`?的方法返回?`true`?,即使訂閱當前處于試用階段:
~~~
if ($user->subscribed('main')) {
//
}
~~~
這個?`subscribed`?方法還可以在?[路由中間件](http://www.hmoore.net/tonyyu/laravel_5_6/786089)?使用,允許你根據用戶的訂閱狀態對路由和控制器進行訪問。
~~~
public function handle($request, Closure $next)
{
if ($request->user() && ! $request->user()->subscribed('main')) {
// 用戶并沒有完成支付...
return redirect('billing');
}
return $next($request);
}
~~~
如果你想要確定用戶是否仍然處于測試階段,你可以使用?`onTrial`?方法。這個方法對于向用戶顯示他們仍然處于試用期的警告是很有用的。
~~~
if ($user->subscription('main')->onTrial()) {
//
}
~~~
可以使用?`subscribedToPlan`?方法可以基于給定的 Stripe / Braintree 計劃 ID 來確定用戶是否訂閱了的該計劃,在本例中,我們將確定用戶的?`main`?訂閱是否激活了?`monthly`?計劃:
~~~
if ($user->subscribedToPlan('monthly', 'main')) {
//
}
~~~
#### 取消訂閱狀態
為了確定用戶是否曾經訂閱,但是已經取消了他們的訂閱,你可以使用?`cancelled`?方法:
~~~
if ($user->subscription('main')->cancelled()) {
//
}
~~~
你還可以確定用戶是否已經取消了訂閱,但是仍然處于訂閱的「寬限期」,直到訂閱完全過期為止。例如,如果用戶在 3 月 5 日取消了原定于 3 月 10 日到期的訂閱,那么用戶將在 3 月 10 日之前進行「寬限期」。請注意,在此期間,`subscribed`?方法仍然返回?`true`?:
~~~
if ($user->subscription('main')->onGracePeriod()) {
//
}
~~~
### 修改訂閱計劃
用戶在你的應用程序中訂閱了之后,他們可能會偶爾想要更改一個新的訂閱計劃。要將一個用戶切換到一個新的訂閱,需將訂閱計劃的標識符傳遞給?`swap`?方法:
~~~
$user = App\User::find(1);
$user->subscription('main')->swap('provider-plan-id');
~~~
如果用戶在試用期,試用期的期限會被保留。另外,如果訂閱的數量存在「份額」,那么該份額也將保持。
如果你想在更改用戶訂閱計劃的時候取消用戶當前訂閱的試用期,可以使用?`skipTrial`?方法:
~~~
$user->subscription('main')
->skipTrial()
->swap('provider-plan-id');
~~~
### 訂閱量
> {note} 訂閱數量僅由 Cashier 的 Stripe 支持。Braintree 沒有一個對應于 Stripe 的「數量」的特性。
有些時候訂閱是會受「數量」影響的。舉個例子,你的應用程序的付費方式可能是**每個賬戶**?$10 /月。你可以使用?`incrementQuantity`?和?`decrementQuantity`?方法輕松的增加或者減少你的訂閱數量:
~~~
$user = User::find(1);
$user->subscription('main')->incrementQuantity();
// 對當前的訂閱數量加 5 ...
$user->subscription('main')->incrementQuantity(5);
$user->subscription('main')->decrementQuantity();
// 對訂閱的當前數量減去 5 ...
$user->subscription('main')->decrementQuantity(5);
~~~
或者,你可以使用?`updateQuantity`?方法設置一個特定的數量:
~~~
$user->subscription('main')->updateQuantity(10);
~~~
`noProrate`?方法可用于更新訂閱的數量,而不會對收費進行定價:
~~~
$user->subscription('main')->noProrate()->updateQuantity(10);
~~~
要獲得更多關于訂閱量的信息,請參考?[Stripe 文檔](https://stripe.com/docs/subscriptions/quantities)。
### 訂閱稅額
要指定用戶在訂閱中支付的稅率百分比,在計費模式上實現?`taxPercentage`?方法,并在 0 到 100 之間返回一個數值,不超過 2 個小數點。
~~~
public function taxPercentage() {
return 20;
}
~~~
`taxPercentage`?方法使你能夠在模型的基礎上應用稅率,這對于一個跨越多個國家和稅率的用戶群來說可能是有幫助的。
> {note}?`taxPercentage`?方法只適用于訂閱付費模式。如果你用 charges 來做 完成一次性收費的,你需要手工指定稅率。
### 取消訂閱
要取消訂閱,只需在用戶的訂閱上調用?`cancel`?方法:
~~~
$user->subscription('main')->cancel();
~~~
當一個訂閱被取消時,Cashier 會自動在你的數據庫中設置?`ends_at`?列。這個列用于知道?`subscribed`?的方法何時應該開始返回?`false`?。例如,如果客戶在 3 月 1 日取消訂閱,但是訂閱計劃直到 3 月 5 日才會結束,`subscribed`方法將會返回?`true`?一直到 3 月 5 日。
你可以使用?`onGracePeriod`?方法確定用戶是否已經取消了訂閱,但是仍然在一個「寬限期」:
~~~
if ($user->subscription('main')->onGracePeriod()) {
//
}
~~~
如果你想馬上取消訂閱,請在用戶的訂閱中調用?`cancelNow`?方法:
~~~
$user->subscription('main')->cancelNow();
~~~
### 恢復訂閱
如果用戶取消了他們的訂閱,可以使用?`resume`?的方法來恢復他們的訂閱。用戶還**必須**在他們的寬限期內才能恢復訂閱:
~~~
$user->subscription('main')->resume();
~~~
如果用戶取消訂閱,然后在訂閱完全過期之前恢復訂閱,他們將不會立即被計費。相反,他們的訂閱將會被重新激活,需要按照原本的支付流程再次進行支付。
### 更新信用卡
`updateCard`?方法可用于更新用戶的信用卡信息,該方法接收一個 Stripe 令牌并設置新的信用卡作為支付源
~~~
$user->updateCard($stripeToken);
~~~
## 試用訂閱
### 有信用卡的情況
如果你想要給你的客戶提供試用期,同時還要收集支付方法信息,那么你應該在創建訂閱時使用?`trialDays`?方法:
~~~
$user = User::find(1);
$user->newSubscription('main', 'monthly')
->trialDays(10)
->create($stripeToken);
~~~
該方法會在數據庫訂閱記錄上設置試用期結束日期,以便告知 Stripe/Braintree 在此之前不要計算用戶的賬單信息。
> {note} 如果客戶沒有在試用期結束之前取消訂閱,訂閱會被自動結算,所以需要在試用期結束之前通知你的客戶。
可以使用用戶實例或訂閱實例上的?`onTrial`?方法判斷用戶是否處于試用期,下面兩個例子作用是等價的:
~~~
if ($user->onTrial('main')) {
//
}
if ($user->subscription('main')->onTrial()) {
//
}
~~~
### 沒有信用卡的情況下
如果你不想在提供試用期的時候收集用戶支付方式信息,只需設置用戶記錄的?`trial_ends_at`?字段為期望的試用期結束日期即可,這通常在用戶注冊期間完成:
~~~
$user = User::create([
// 填充其他用戶屬性...
'trial_ends_at' => now()->addDays(10),
]);
~~~
> {note} 確保已添加?`trial_ends_at`?[日期修改器](http://www.hmoore.net/tonyyu/laravel_5_6/786275#_94)?到模型定義。
Cashier 把這種類型的試用引用為「一般體驗」。因為它并沒有關聯任何已存在的訂閱。如果當前的日期沒有超過?`trial_ends_at`?的值, 那么?`User`?實例上的?`onTrial`?方法將返回?`true`?:
~~~
if ($user->onTrial()) {
// 用戶在試用期內...
}
~~~
如果你希望明確地知道用戶處于「一般」的試用期,并且還沒有創建實際的訂閱,那么你可以使用?`onGenericTrial`?方法:
~~~
if ($user->onGenericTrial()) {
// 用戶在 「一般」 試用期內...
}
~~~
一旦你準備好為用戶創建實際的訂閱,可以使用?`newSubscription`?方法:
~~~
$user = User::find(1);
$user->newSubscription('main', 'monthly')->create($stripeToken);
~~~
## 處理 Stripe Webhooks
Stripe 和 Braintree 都可以通過 webhooks 通知應用各種事件,要處理 Stripe webhooks,需要定義一個指向 Cashier webhook 控制器的路由,這個控制器將會處理所有輸入 webhook 請求并將它們分發到合適的控制器方法:
~~~
Route::post(
'stripe/webhook',
'\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);
~~~
> {note} 一旦注冊好控制器后,還要在 Stripe 控制面板中配置 webhook URL。
默認情況下,這個控制器將會自動對支付失敗次數(這個次數可以在 Stripe 設置中定義)過多的訂閱進行取消;此外,我們很快會發現,你可以擴展這個控制器來處理任何你想要處理的 webhook 事件。
#### Webhooks & CSRF 保護
因為 Stripe webhooks 需要繞過 Laravel 的?[CSRF 保護](http://www.hmoore.net/tonyyu/laravel_5_6/786094),一定要在?`VerifyCsrfToken`?中間件中列出 URI ,或者將其置于?`web`?中間件組之外:
~~~
protected $except = [
'stripe/*',
];
~~~
### 定義 Webhook 事件處理器
Cashier 對于失敗的支付自動進行取消訂閱的處理,但是如果你有其他的 Stripe webhook 事件,你想要處理,可以簡單地擴展 Webhook 控制器。你的方法名應該與 Cashier 期望的約定相符,具體來說,方法應該是用?`handle`?前綴,和你希望處理的 Stripe webhook 的「駝峰」名稱。例如,如果你希望處理?`invoice.payment_succeeded`?webhook ,你應該添加一個?`handleInvoicePaymentSucceeded`?方法到控制器:
~~~
<?php
namespace App\Http\Controllers;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
class WebhookController extends CashierController
{
/**
* 處理 Stripe webhook.
*
* @param array $payload
* @return Response
*/
public function handleInvoicePaymentSucceeded($payload)
{
// 處理事件
}
}
~~~
接下來,?`routes/web.php`?文件中定義一個到你的 Cashier 控制器的路由:
~~~
Route::post(
'stripe/webhook',
'\App\Http\Controllers\WebhookController@handleWebhook'
);
~~~
### 失敗的訂閱
如果用戶的信用卡過期怎么辦?不用擔心 — Cashier webhook 控制器可以輕松為你取消該用戶的訂閱,正如上面所提到的,你所需要做的只是將路由指向該控制器:
~~~
Route::post(
'stripe/webhook',
'\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);
~~~
就是這樣,失敗的支付將會被控制器捕獲和處理,該控制器將會在 Stripe 判斷訂閱支付失敗次數(通常是3次)達到上限時取消該用戶的訂閱。
## 處理 Braintree Webhooks
Stripe 和 Braintree 都可以通過 webhooks 通知應用各種事件,要處理 Braintree webhooks,需要定義一個指向 Cashier webhook 控制器的路由,這個控制器將會處理所有輸入 webhook 請求并將它們分發到合適的控制器方法:
~~~
Route::post(
'braintree/webhook',
'\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);
~~~
> {note} 一旦注冊好控制器后,還要在 Braintree 控制面板中配置 webhook URL
默認情況下,該控制器將自動處理在多次失敗的支付嘗試后自動取消該訂閱(根據你的 Braintree 設置所定義);但是,我們很快就會發現,你可以擴展這個控制器來處理任何你喜歡的 webhook 事件。
#### Webhooks & CSRF 保護
因為 Braintree webhooks 需要繞過 Laravel 的?[CSRF 保護](http://www.hmoore.net/tonyyu/laravel_5_6/786094),所以一定要在?`VerifyCsrfToken`?中間件中列出這個 URI ,或者列出?`web`?中間件組之外的路由:
~~~
protected $except = [
'braintree/*',
];
~~~
### 定義 Webhook 事件處理器
Cashier 對于失敗的支付自動進行取消訂閱的處理, 但是如果你想要處理額外的 Braintree webhook 事件,可以簡單的擴展一下 Webhook 控制器。定義的方法名需要與 Cashier 約定的格式保持一致,特別的是,方法名應該以?`handle`?為前綴,然后以 「駝峰」命名的方式加上你要處理的 Braintree webhook 的名稱。例如,你想處理?`dispute_opened`webhook,則需要添加一個?`handleDisputeOpened`?到控制器中:
~~~
<?php
namespace App\Http\Controllers;
use Braintree\WebhookNotification;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
class WebhookController extends CashierController
{
/**
* 處理 Braintree webhook.
*
* @param WebhookNotification $webhook
* @return Response
*/
public function handleDisputeOpened(WebhookNotification $notification)
{
// 處理事件
}
}
~~~
### 訂閱失敗
如果客戶的信用卡過期了怎么辦?不用擔心,Cashier 會有一個 Webhook 控制器,它可以很容易地取消客戶的訂閱。如上所述,你所需要做的就是指定一個路由到該控制器:
~~~
Route::post(
'braintree/webhook',
'\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);
~~~
就是這樣,失敗的支付將會被控制器捕獲和處理,該控制器將會在 Braintree 判斷訂閱支付失敗次數(通常是3次)達到上限時取消該用戶的訂閱。不要忘記在 Braintree 控制面板中配置 webhook URI。
## 一次性支付
### 簡單支付
> {note} 當使用 Stripe 時,?`charge`?法會接收?**應用所使用貨幣對應的最小單位金額**。然而,當使用 Braintree 時,你應該將全部的美元金額傳遞給?`charge`?方法:
如果你想對訂閱客戶的信用卡收取「一次性」費用,可以在可計費模型實例上使用?`charge`?方法:
~~~
// Stripe 接收分為單位的費用...
$user->charge(100);
// Braintree 接收美元為單位的費用...
$user->charge(1);
~~~
`charge`?方法接收一個數組作為第二個參數,允許你傳遞任何你想要傳遞的底層 Stripe/Braintree 賬單創建參數,創建賬單時我們可以參考 Stripe 或者 Braintree 文檔提供的可用選項:
~~~
$user->charge(100, [
'custom_option' => $value,
]);
~~~
當支付失敗?`charge`?方法將拋出異常,如果支付成功,該方法會返回完整的 Stripe / Braintree 響應:
~~~
try {
$response = $user->charge(100);
} catch (Exception $e) {
//
}
~~~
### 費用與發票
有時候你需要創建一個一次性支付并且同時生成對應發票以便為用戶提供一個PDF單據。?`invoiceFor`?方法就是做這個的。例如,讓我們給客戶開具一個 $5.00 的「一次性費用」發票:
~~~
// Stripe 接收分為單位的費用...
$user->invoiceFor('One Time Fee', 500);
// Braintree 接收美元為單位的費用...
$user->invoiceFor('One Time Fee', 5);
~~~
該單據會通過用戶信用卡立即支付,?`invoiceFor`?方法還可以接收一個數組作為第三個參數,從而允許你傳遞任意你希望的選項到底層 Stripe/Braintree 支付創建:
~~~
$user->invoiceFor('One Time Fee', 500, [
'custom-option' => $value,
]);
~~~
如果你使用 Braintree 作為你的賬單提供者, 你必須在調用?`invoiceFor`?方法時包含一個?`description`?選項:
~~~
$user->invoiceFor('One Time Fee', 500, [
'description' => '發票描述寫在這里',
]);
~~~
> {note}?`invoiceFor`?方法在當多次嘗試失敗支付后也會產生一個 Stripe 發票。如果你不需要為失敗重試的支付生成發票,你需要在第一次失敗結算是就調用 Stripe 的 API 關閉它們。
## 發票
你可以使用?`invoices`?方法輕松獲取賬單模型的發票數組:
~~~
$invoices = $user->invoices();
// 結果包含處理中的發票...
$invoices = $user->invoicesIncludingPending();
~~~
當列出客戶發票時,你可以使用發票的輔助函數來顯示相關的發票信息。例如,你可能想要在表格中列出每張發票,從而方便用戶下載它們:
~~~
<table>
@foreach ($invoices as $invoice)
<tr>
<td>{{ $invoice->date()->toFormattedDateString() }}</td>
<td>{{ $invoice->total() }}</td>
<td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>
</tr>
@endforeach
</table>
~~~
### 生成 PDF 發票
從路由或控制器中,使用?`downloadInvoice`?方法生成發票的 PDF 下載。該方法將會自動生成相應的 HTTP 響應發送下載到瀏覽器:
~~~
use Illuminate\Http\Request;
Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) {
return $request->user()->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
'product' => 'Your Product',
]);
});
~~~
- 前言
- 翻譯說明
- 發行說明
- 升級指南
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- Homestead
- Valet
- 部署
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- Facades
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- URL
- Session
- 表單驗證
- 錯誤
- 日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全相關
- 用戶認證
- Passport OAuth 認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試相關
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Scout 全文搜索
- Socialite 社會化登錄