カテゴリー: Server

Laravel Cashierでサブスクリプションを実装する

はじめに

Laravel Cashierは Laravel公式のパッケージで、Stripe決済に必要なバックエンドの実装を肩代わりしてくれるパッケージです。
今回は、支払い方法の登録、サブスクリプションの作成について紹介します。

Stripeの準備

はじめに、Stripeでアカウントを作成します。
管理画面で、[開発者]>[APIキー]にある、「公開可能キー」と「シークレットキー」を控えておきます。

Laravel Cachierの初期設定

インストール

composerを使用してインストールします。

$ composer require laravel/cashier

インストール後、必要なマイグレーションファイルが追加されるため、マイグレーションを実施します。

$ php artisan migrate

APIキーの設定

envファイルに、控えておいたAPIキーを設定します。

STRIPE_KEY=公開可能キー
STRIPE_SECRET=シークレットキー

Userモデルへの実装

Userモデル、 Billableトレイトを使用するようにします。
これにより、Webサイトの利用者が、課金・決済することができるようになります。

支払い方法の登録

支払い方法の登録

コントローラから実装していきます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class UserController extends Controller
{
    public function getPaymentMethod()
    {
        // クレジットカードの登録に必要なシークレットをStripeから取得する
        return view('users.payment_method', [
            'intent' => Auth::user()->createSetupIntent()
        ]);
    }

    public function postPaymentMethod(Request $request)
    {
        // Stripe顧客を作成する
        $stripeCustomer = Auth::user()->createAsStripeCustomer();
        // トークンを受け取り、Stripeに検証した上で、usersテーブルに、支払い情報を登録する。
        Auth::user()->updateDefaultPaymentMethod($request->payment_method);
        return response()->redirectTo('/users/payment_method');
    }
}

次に、ビューです。

@extends('layouts.app')

@section('content')
    <div class="container">
        <h3>支払い方法の登録</h3>
        カード名義人 <input id="card-holder-name" type="text">

        <!-- Stripe要素のプレースホルダ -->
        <div id="card-element"></div>

        <button id="card-button" data-secret="{{ $intent->client_secret }}">
            登録する
        </button>

        <form method="post" action="/users/payment_method" id="updateForm">
            @csrf
            <input type="hidden" name="payment_method">
        </form>

        // StripeのJS SDKの読み込み
        <script src="https://js.stripe.com/v3/"></script>

        <script>
            const stripe = Stripe('{{ env('STRIPE_KEY') }}');

            const elements = stripe.elements();
            const cardElement = elements.create('card');

            cardElement.mount('#card-element');

            const cardHolderName = document.getElementById('card-holder-name');
            const cardButton = document.getElementById('card-button');
            const clientSecret = cardButton.dataset.secret;

            cardButton.addEventListener('click', async (e) => {
                // カード情報の登録 (Stripeとの通信)
                const { setupIntent, error } = await stripe.confirmCardSetup(
                    clientSecret, {
                        payment_method: {
                            card: cardElement,
                            billing_details: { name: cardHolderName.value }
                        }
                    }
                );

                if (error) {
                    alert(error.message);
                } else {
                    // クレジットカードの登録に成功したので、Laravel側にトークンをPostする
                    const updateForm = document.getElementById('updateForm');
                    updateForm.payment_method.value = setupIntent.payment_method;
                    updateForm.submit();
                }
            });

        </script>
    </div>
@endsection

Laravelの公式ドキュメントのソースコードをベースに作成しています。
支払い情報を登録する際は、コントローラー側で、 $user->createSetupIntent()を呼び出し、結果をそのままビューに渡します。
ビュー側の登録ボタンでは、 <button id="card-button" data-secret="{{ $intent->client_secret }}">となっており、シークレットを設定します。

ビュー側は、基本的にStripe JS SDKを使用します。カード情報はStripe側に登録させて、Laravel側にはトークンのみを受け取るようにします。
支払い情報は、Stripe顧客を作成しないと登録できないため、先に作成した上で、カード情報を登録します。

サプスクリプション

サブスクリプションを作成するには、 $user->newSubscription()メソッドを使用して作成します。
コントローラーのコードです。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class UserController extends Controller
{
    public function postSubscriptions(Request $request)
    {
        // 登録済みのデフォルト支払い方法を使用
        $paymentMethod = Auth::user()->defaultPaymentMethod()->paymentMethod;
        Auth::user()->newSubscription('default', 'プランID')->create($paymentMethod);
        return response()->redirectTo('/users/subscriptions');
    }
}

newSubscription()メソッドの第一引数には、サブスクリプション の名前を付けます。この名前は、Laravelアプリ内のsubscriptionテーブルで管理されるもので、後からサブスクリプション の状況を確認するときにも使用します。
プランIDは、Stripeに登録済みのプランIDを指定する必要があります。
Stripe管理画面で商品を登録し、価格を登録すると表示される「API ID」を指定してください。

サブスクリプション状況を確認するには、 $user->subscribed('default')とすることで、確認することができます。

試用期間

試用期間を設定したい場合は、サプスクリプション作成時に設定します。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class UserController extends Controller
{
    public function postSubscriptions(Request $request)
    {
        $paymentMethod = Auth::user()->defaultPaymentMethod()->paymentMethod;
        Auth::user()->newSubscription('default', 'price_id')
            ->trialDays(7) // 7日間のトライアル
            ->create($paymentMethod);
        return response()->redirectTo('/users/subscriptions');
    }
}

サブスクリプション作成時に、 trialDays()メソッドを使用することで、試用期間を設定できます。
試用期間を設定すると、Stripe側で請求日が試用期間後の日付となり、その日以降は自動的に請求が発生します。

おまけ

Laravel Cashierには、Stripe PHP SDKがそのまま入っているため、直接使用することもできます。
例えば、サブスクリプション作成時に必要となる、プランは、Stripe SDKを使用して動的に増やすこともできます。
プランを作成し、そのプランIDを使用してサブスクリプションを作成するサンプルコードです。

// プランの作成
$plan = Plan::create([
                'amount' => 1000, // 1000円
                'currency' => 'jpy',  // 日本円決済
                'interval' => 'month', // サブスクリプション の周期
                'product' => ['name' => 'プレミアムプラン'] // 商品情報
]);

// 作成したプランのIDでサプスクリプションを作成する
Auth::user()->newSubscription('default', $plan->id)
            ->create($paymentMethod);

さいごに

いかがでしたか。Laravel Cashierを使用すると、Stripeの実装に必要なバックエンドの実装が、かなり軽減されることが分かりました。次回は、Laravel CashierのWeb hookや、複数の支払い方法を管理する方法について紹介したいと思います。

おすすめ書籍

カイザー

シェア
執筆者:
カイザー
タグ: phplaravel

最近の投稿

Goの抽象構文木でコードを解析する

はじめに Goでアプリケーショ…

1日 前

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

4週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前