LaravelとStripeを使って決済機能を持つショッピングサイトを作った



約1年前にWeb開発の業務を担当させて頂きそこからマイペースにLaravelの勉強をしてきました。
勉強してきたことを1つの成果物としてまとめたいなと思い決済機能を持つ簡単なショッピングサイトを作りました。

人によっては1ヶ月以内で出来る様な出来で恐縮ですがベーシック認証をかけた状態でherokuにデプロイをしました。
SSLの設定や画像ファイルの格納先の権限やらでまだ完璧にデプロイ出きた訳では無いですが、社内でのみ公開が出来る様にしたいと考えております。

ここでは主に画面のキャプチャを用いて画面構成やどの様に作り込みをしたかをまとめていきます。
githubにソースコードを上げているのでソースコードの詳細はそちらをご覧頂ければと存じます。
自習やポートフォリオサイトを作ってみたいという方の助けになれれば幸いです。

*決済はStripeを利用したクレジットカード決済となっています。(テストモードです。) 
*以前書いた記事と重複している箇所は説明を割愛します。

# 動作環境について
OS:macOS High Sierra
version: 10.13.6

Docker(Engine):18.09.1


#### 対象ブラウザ
GoogleChrome:72以上

#### 開発環境
centOS:7.5
Laravel:5.6
PHP:7.2
MySQL:5.7
PostgreSQL:10.6
APache2.4

#### 外部サービス
[Mailgun](https://app.mailgun.com)
[Stripe](https://stripe.com/jp)


# 参考資料
[【簡単・オシャレ】PHPでstripeの決済を導入する手順【決済システム導入】](https://qiita.com/4_R_R_S/items/c9d8e949c9d9b2fcd0d7)
[【初級編】LaravelでStripeを使って単発決済を実装する](https://takkublog.net/stripe02/)


# TOPページ

現在DBに登録されている商品が表示されています。
キーワード入力による商品の検索も可能です。

![FireShot Capture 6 - ECshop - http___shop1.localhost_.png](https://qiita-image-store.s3.amazonaws.com/0/238861/dc7f0ef0-6c8a-0013-a498-cf17cce48ec9.png)


TOPページでは決済が出来ないようになっています。
管理者は管理者ログインのリンクを、お客様はお客様ログインのリンクを押下して貰うことでログインページに遷移します。
お客様の新規登録の場合は新規登録のリンクを押下することでログインページに遷移します。


# ログイン・ユーザー画面

管理者と顧客それぞれのログイン関連の処理については以前書いた記事にまとめています。

[adminテーブルを使って認証する方法](https://qiita.com/maejima_f/items/e153c097e2912d2d75c1)
[customerテーブルを使って認証する方法](https://qiita.com/maejima_f/items/8349582f43a8a5ce04a61)

パスワード再設定に使うメールはMailgunを使いますが、送信先が限定されているので本番環境ではsmtpを立てた方が良さそうです。


# 管理者画面

TOPページと同様に登録されている商品の一覧が表示されています。
TOPページと異なる点は各商品ごとに編集、画像アップロード、削除の処理を行えるボタンを置いていることです。

![FireShot Capture 9 - ECshop - http___shop1.localhost_admin_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/4c38d41f-063e-ce09-59de-75ae83e0f290.png)


ファイルアップロードについても[別の記事](https://qiita.com/maejima_f/items/7691aa9385970ba7e3ed)でまとめています。


右上のプルダウンを押すとメニュー画面が出てきます。
ここから管理者のホーム画面への遷移、管理者登録、商品登録、ログアウトを行います。

![スクリーンショット 2019-02-11 16.27.48.png](https://qiita-image-store.s3.amazonaws.com/0/238861/0afe425d-b82e-2e88-24e1-d7b2f060cddb.png)


#### 新商品登録
商品登録画面では商品名、価格、説明文を入力できます。

![FireShot Capture 10 - ECshop - http___shop1.localhost_admin_goods_regist.png](https://qiita-image-store.s3.amazonaws.com/0/238861/110cd622-13d4-ae32-9ac8-bd221c5c3127.png)


上記3項目はバリデーションファイルにて入力条件を定めることで誤ったデータがDBに挿入されることを防いでいます。

```PHP
public function rules()
{
    return [
        'goods_name'  => 'required|string|max:50',                      // 必須|文字列|最大50文字
        'price'       => 'required|integer|min:1|digits_between:1,6',   // 必須|最小値:1|数値かつ1桁~6桁
        'goods_text'  => 'nullable|string|max:120',                     // null可|文字長120文字以内
    ];
}
```

入力誤りがあればメッセージが表示されます。

![FireShot Capture 11 - ECshop - http___shop1.localhost_admin_goods_regist.png](https://qiita-image-store.s3.amazonaws.com/0/238861/f97dbe0f-880d-38f9-87dc-9b0f1cd36f30.png)


最終的な入力内容に誤りが無いか確認する為に確認画面を設けています。


![FireShot Capture 12 - ECshop - http___shop1.localhost_admin_goods_confirm.png](https://qiita-image-store.s3.amazonaws.com/0/238861/41fdb818-2d68-b61f-f814-611638807110.png)

「登録する」ボタンを押下すると商品の登録が完了します。

![FireShot Capture 13 - ECshop - http___shop1.localhost_admin_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/0829d5f2-9837-c512-ac45-858bece0323d.png)


#### 商品情報編集

各商品の「編集」ボタンを押下します。
画面構成自体は新規登録時と違いはありません。
商品ごとにDBに登録されている値が予め入力欄に表示されます。

![FireShot Capture 15 - ECshop - http___shop1.localhost_admin_goods_edit_115.png](https://qiita-image-store.s3.amazonaws.com/0/238861/b83566e0-27f5-1ea5-f490-5d2f1649147c.png)


編集し終えたら確認をし、最後にデータの更新をかけます。

![FireShot Capture 24 - ECshop - http___shop1.localhost_admin_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/430c56c9-f8c6-544b-3435-fdca3de77c80.png)


#### 商品削除

「削除」ボタンを押すと確認のアラートが表示されます。「OK」を押すと即座に商品の削除が実行されます。

![FireShot Capture 18 - ECshop - http___shop1.localhost_admin_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/4c8272cc-3399-68b5-b2ba-723c5ae0fbff.png)



# 顧客画面

TOPページと同様に登録されている商品の一覧が表示されています。
TOPページと異なる点は商品のカートへの格納と削除を行うボタン、最終的な購入手続きを行うボタンがあることです。

![FireShot Capture 19 - ECshop - http___shop1.localhost_customer_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/9377009b-f095-eebf-7beb-fae30e3e25f7.png)


右上のプルダウンを押すとメニュー画面が出てきます。
ここから顧客のHome画面への遷移、ログアウトを行います。

![スクリーンショット 2019-02-11 16.58.09.png](https://qiita-image-store.s3.amazonaws.com/0/238861/d4858909-4db1-7e36-2531-27f468dc52a5.png)



#### カートに入れる

カートに何も商品を入れないまま購入手続きをしようとしても出来ない様になっています。

![FireShot Capture 21 - ECshop - http___shop1.localhost_customer_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/af4d4d4f-9a30-62d7-851d-cedb3fdd7e7f.png)


「カートに入れる」ボタンを押下することで該当の商品をカートに入れることが出来ます。
1回のボタン押下によりカートに入れることが出来る数量は1つとなっています。

![FireShot Capture 22 - ECshop - http___shop1.localhost_customer_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/c228b725-a8e6-c2f6-1a57-40179e242b89.png)



#### カートから外す

「カートから外す」ボタンを押下することで該当の商品をカートから外すことが出来ます。
1回のボタン押下によりカートから外すことが出来る数量は1つとなっています。

![FireShot Capture 23 - ECshop - http___shop1.localhost_customer_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/ab000ade-6313-0e28-5cc2-2f9f30526fe0.png)


#### 購入内手続き
ホーム画面から「購入内手続きへ」ボタンを押すと購入内容の確認画面に遷移します。


確認画面ではカートに入れた商品のデータと購入数、合計決済金額が表示されています。
確認という観点からこの画面内では一切の商品や購入数の変更が出来ない様になっています。

![FireShot Capture 26 - ECshop - http___shop1.localhost_customer_cart_payment_confirm.png](https://qiita-image-store.s3.amazonaws.com/0/238861/1e803862-3ecd-52a9-8ef2-d28fb3d4b960.png)


「購入する」ボタンを押下するとstripeの決済画面が表示されます。(テストモードです。)
メールアドレス、カード番号、利用期限、セキュリティコードを入力して「*を支払う」と書いてあるボタンを押下することでクレジットカード決済が完了します。

![FireShot Capture 27 - ECshop - http___shop1.localhost_customer_cart_payment_confirm.png](https://qiita-image-store.s3.amazonaws.com/0/238861/bf546c3d-b459-406d-baba-b6e4c4634a46.png)

決済処理後はホーム画面に遷移し、決済完了のモーダルが表示されます。

![FireShot Capture 28 - ECshop - http___shop1.localhost_customer_home.png](https://qiita-image-store.s3.amazonaws.com/0/238861/456e9afa-6d3d-8da9-3201-e7daf51e3c13.png)


決済の実装で躓いた箇所がモーダルを表示する為のボタンの実装でした。


stripeのリファレンス等では下記の様な形式で記述すると書いてあります。
scriptタグ内でボタンを表示させていることを理解出来ていなかったのでどうやって任意の位置にボタンを配置すれば良いのだろうと悩んでいました。

```PHP
<form action="{{ route('') }}" method="POST">
    <script
            src="https://checkout.stripe.com/checkout.js" class="stripe-button"
            data-key="{{ env('STRIPE_PUBLIC_KEY') }}"
            data-amount=1000
            data-name="EC Shop"
            data-label="決済をする"
            data-description="Online shopping by Stripe"
            data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
            data-locale="auto"
            data-currency="JPY">
    </script>
</form>
```

scriptタグの直前に下記のaタグを記述することでキャプチャ通りの配置でボタンを実装することが出来ました。

```PHP
<a class="btn btn-primary" href="/customer/home">戻る</a>
```

また、Laravelでデフォルトで用意されている。app.jsがstripeの動作を妨げているらしく、モーダル画面が開くことが出来ませんでした。
この画面だけjsの利用を限定させるなどの工夫が必要でした。


# まとめ

以上が、今回私が作成したショッピングサイトの構成となります。

特に時間のかかった作業は認証、ファイルアップロード、決済機能の実装に関してです。

Laravelではデフォルトでusersテーブルを使った管理者機能を利用出来る様になっていますが、別のテーブルを利用して管理者と顧客両方のログイン機能を実装するのに綿密な調査が必要でした。
ファイルアップロード機能は業務含めて初めての試みだったのでバリデーションを考慮して実装するのに時間がかかりました。
決済機能の実装も初めての試みであり今回はAPIを利用させて頂きましたが、深いところを理解出来ていないのが正直な話です。


もっと検討すべき仕様などがございますが時間的な都合で出来なかったことが多々あります。
また、本番公開の段階で発生した修正などもあり、実際に作っている中で自分の力不足を痛感することが多々ございました。

今回の反省点を踏まえてもっと品質の良いプロダクトを作れる様に精進したいと思います。

ご覧頂きありがとうございました。