【Laravel】未ログイン状態での操作を保留して、自動ログイン→操作実行する方法

# 概要

Laravelで**「未ログイン状態での操作を保留して、自動ログイン→操作実行する」**コードの例を書きます。参考にしていただけたら幸いです。

なにを言ってるのか分かりづらいので、実例で紹介します。

## やりたいことの具体例

ダンスレッスン予約サイトを例に仕様を説明します。

画面下部の「予約する」ボタンを押すだけで「ツイッター連携ログイン（許可承諾）→予約」がシームレスに実行できるようにしました。

<img width="886" alt="スクリーンショット 2019-12-07 18.05.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227609/66e739ff-4206-eee8-a24b-89c90f52608d.png">


画像の「予約する」ボタンを押すと、Twitter認証によるログインが行われて予約完了します。お手軽🙌

これまで利用していた予約サービスは、予約の前に「ユーザー登録→ログイン」が必要でした。これを取り除き、予約までのめんどくささを最大限に取り除きました。

特に今回はTwitter連携のユーザー登録に特化することで「どのSNSと連携するかの選択する」の手間もさっくり削りました😁

# 実現方法

こちらもダンスレッスン予約サイトを例に説明します。
例ではTwitter連携になっていますが、他のSNS連携ログインでも実現可能ですので、必要に応じて応用してみてください。

【前提】
laravel v5.8.19
php v7.3.8

## 大まかな処理の流れ

1. ユーザーが予約操作する
2. （未ログインの場合）Cookieに予約操作情報を保存する
3. Twitter認証先にリダイレクトし、OAuth認証を行う
4. （初回ログインの場合）ユーザーの登録処理を行う
5. ログインし、Cookieの情報をもとに予約処理を実行する


## 実装の説明

### 予約操作〜OAuth認証先にリダイレクト

まずはこの辺の処理に相当するコードを紹介

1. ユーザーが予約操作する
2. （未ログインの場合）Cookieに予約操作情報を保存する

```php:ReserveController.php
    public function create(Request $request)
    {

        // 未ログインの場合は、予約操作をCookieに保存してTwitter認証へリダイレクト
        if (Auth::check() === false) {
            Cookie::queue(Cookie::make('noAuthReserveRequest', $request->lesson_id, 30));
            return redirect('/login/twitter');                     
        }
        // 以下はログイン済みの場合の処理。省略
```

### Twitter認証先にリダイレクトし、OAuth認証を行う

`return redirect('/login/twitter')`の後の処理はLaravelでTwitter認証します。こちらは[Socialiteの使い方を世界一丁寧に解説した](https://php-junkie.net/framework/laravel/socialite/)を参照ください。

**世界一丁寧だからご安心を😊**

この記事はこみゅーの[ボス（むちょこさん）](https://twitter.com/aya_lachelier)が書いてくれてます。わからない場合は[TwitterDB](https://twitter.com/aya_lachelier)でクレームを入れると喜びます。本人いわくドMらしいので。~~僕は別件で５回ぐらいクレーム入れてます~~

話ずれたな・・・

### ユーザーの登録処理を行う〜予約処理を実行する

さあ残りの処理を説明します！
6. （初回ログインの場合）ユーザーの登録処理を行う
7. ログインし、Cookieの情報をもとに予約処理を実行する


```php:LoginController.php
    /**
     ** OAuth認証の結果受け取り
     **
     ** @param str $provider
     ** @return \Illuminate\Http\Response
     **/
    public function handleProviderCallback($provider)
    {
        // 直接関係ないエラー処理等は説明のために省いています
        $providerUser = \Socialite::with($provider)->user();
        Auth::login(SocialService::findOrCreate($providerUser, $provider));

        if (Auth::check()) {

            //ログイン前にしてた予約操作を実行する
            $noAuthReserveRequest = Cookie::get('noAuthReserveRequest');
            \Cookie::queue(\Cookie::forget('noAuthReserveRequest'));

            //予約IDがCookieに入力されている場合は予約する
            if (!empty($noAuthReserveRequest)) {

                //予約の重複を防ぐ
                if (0 === Reserve::where('user_id', Auth::user()->id)->where('lesson_id', $noAuthReserveRequest)->count()) {
                    //ログイン前にした予約操作を実行
                    $reserve = new Reserve();
                    $reserve->fill(['user_id' => Auth::user()->id]);
                    $reserve->fill(['lesson_id' => $noAuthReserveRequest]);
                    $reserve->save();

                    return view('course.reserve')->with(['course' => $reserve->lesson->course, 'lesson' => $reserve->lesson]);
                }
            }
```

# まとめ

ファットコントローラで吐き気がするコードですね。
そのうちリファクタリングしたいです。

ちなみに、実際にここから僕のダンスレッスンを予約できます。

ダンス未経験者大歓迎！ダンスで運動不足を解消しよう！
毎月最終土曜、渋谷駅徒歩5分、15時〜16時、¥1000です。
https://eedance.funspot.tokyo/

以上になります。