LaravelのCashierがバージョンアップした際、それまでの機能が一部、使えなくなりました。
そのため、少し前の記事で解説されている方法を使うと「$paymentMethodがない」と言われ、エラーになります。
そうとも知らず、わたしは無駄に試行錯誤をしてしまいました><
同じように、このトラップにかかってしまった方のために、原因と対策を記事にします。

この経験が、他の方の役に立てば、少しは報われます。
Laravel8とSTRIPEの連携で $paymentMethod が設定できず悩んでいる方へ
まずは、なぜこれまでの方法が使えなくなったのか、問題の原因から説明していきますね。
なぜこれまでの方法が使えなくなったのか
Laravelのマニュアルでは、サブスクリプションを作成する際のコードとして、下記が提示されています。
$user->newSubscription(‘default’, ‘price_premium’)->create($paymentMethod);
この $paymentMethodは、少し前までなら、下記のようにコントローラーに記述すればOKだったようです。
$user = User::find($id);
$user->newSubscription(‘main’, ‘Plan Id’) ->create($request->stripeToken);
検索をかけると、このようにサブスクリプション作成を行うよう解説しているものが結構あります。
ただ、2019年8月にCashier10がリリースされた際、上記の方法は使えなくなりました。
がんばって行おうとすると「$paymentMethodがない」「無効だ」といったエラーがでます。
対策① Cashierを古いバージョンで使う
ではどうすれば良いのかですが、一番シンプルなのは、Cashierを古いバージョンで使うことです。
通常は、下記のコードによって最新版の cachierパッケージをインストールできます。
このとき、バージョンを指定することで、古いcashierをインストールできます。
対策② balde.phpファイル側で$paymentMethodを設定する
もうひとつの方法はblade.phpファイル側で$paymentMethodを設定しておくこと。
こちらのほうが正当法ですが、面倒です。
ざっとコードをお見せします。
ビュー表示用のコントローラー
public function subscription(Request $request){
$user=Auth::user();
return view('test.subscription', [
'intent' => $user->createSetupIntent()
]);
ビューのフォーム部分
ビューのフォーム部分は、下記のようにしておきます。
なお外見はすごくテキトウです^^;
ご了承ください。
<form action="{{route('ルート名')}}" method="post" id="payment-form">
@csrf
<input type="text" id="card-holder-name">
<div id="card-element"></div>
<div id="card-errors" role="alert"></div>
<button class="btn btn-primary" id="card-button"
data-secret="{{ $intent->client_secret }}">
Submit Payment
</button>
</form>
ビューのJavascript部分
var stripe = Stripe('STRIPE KEYの情報');
var elements = stripe.elements();
// 外見を整える
var style = {
base: {
color: "#32325d",
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#aab7c4"
}
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a"
}
};
var card = elements.create('card', {style: style});
card.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) => {
const { setupIntent, error } = await stripe.confirmCardSetup(
clientSecret, {
payment_method_data: {
card: card,
billing_details: { name: cardHolderName.value }
}
}
);
if (event.error) {
// ユーザーに"error.message"を表示
const displayError=document.getElementById('card-errors');
displayError.textContent = event.error.message;
console.log('error');
} else {
// カードの検証に成功
stripePaymentHandler(setupIntent);
}
});
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
});
function stripePaymentHandler(setupIntent) {
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripePaymentMethod');
hiddenInput.setAttribute('value', setupIntent.payment_method);
form.appendChild(hiddenInput);
form.submit();
}
フォーム送信後のコントローラー
フォームをポストした後、コントローラーの処理は下記の感じになります。
$planは別途定義してください。
$paymentMethod=$request->input('stripePaymentMethod');
$user->newSubscription('default', $plan )->create($paymentMethod);
より詳しい手順はこちらをどうぞ!
さいごに
今回の件で、少し前に書かれた方法でも、既に使えない可能性があることを改めて学びました。
正直、分かったときはガックリきましたが Σ( ̄ロ ̄lll)ガーン
今後も、色々な変化は起こるかもしれません。
このエラーのもとになった変更は、そもそも、認証に関する規制が強まったことによって起こっています。
詳しく解説してみたので、気になる方は、こちらの記事をお読みください。
別の記事でもLaravelとStripe連携を解説しているので、トラブルなどがあれば、関連記事をチェックしてくださいね。




コメント