Laravel 7で簡易的なECサイトを作る+Twitter OAuth ログインを実装する

以下のサイトを参考に、ECサイトを構築します。
エラーが起こった箇所のみ書いていますが、結構長いです。
・[Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る](https://note.com/mukae9/n/n12cc13fd4f90?magazine_key=mf7a8ea438ba1)
・[TwitterAPI アカウント申請〜許可まで【2020年版】](https://note.com/mukae9/n/nb249bcfe6ee9)
・[Laravel6.0+SocialiteでTwitterログインを実装する](https://note.com/mukae9/n/n91ff7bccfcd8)
・[Laravel 6.5 と Socialite で Twitter OAuth ログインを実現する](https://econosys-system.com/blog/archives/419)

※ソースコードは[github](https://github.com/neneta0921/ec_app)にて公開しているので、宜しけば参考にしてください。

##作業環境
OS：Windows 10 HOME Edition（ver.2004）
Laravel：7.15.0
Xampp：7.4.6
Composer：1.10.7
Node.js：13.9.0

##環境構築
Laradockではなく、いつもどおりのXamppで行いました。

###Laravelのインストール
下記のコマンドを実行すると、Laravelのインストールができます。今回は「ec_app」というアプリ名にしました。

```
$ cd c:\xampp\htdocs
$ composer create-project laravel/laravel ec_app --prefer-dist
```

###デバックバーのインストール
以下のコマンドを実行して、デバックバーのインストールします。

```
$ composer require barryvdh/laravel-debugbar
```

###Laravelのタイムゾーンと言語設定
「config/app.php」を編集します。

```config/app.php
70行目　'timezone' => 'Asia/Tokyo',
83行目　'locale' => 'ja',
```

###データベースの言語設定
「config/database.php」を編集します。

```config/database.php
55行目　'charset' => 'utf8',
56行目　'collation' => 'utf8_unicode_ci',
```

###データベースの設定
xamppのMySqlのAdminボタンを押してphpMyAdminを起動し、今回使用するデータベースを作成します。
![202006241817.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/5d450a2c-e870-5e79-7e12-639cd1fb49d9.png)
今回はデータベース名は「ec_app_db」としていますが、任意の名前でOKです。だたし、言語は「utf8_general_ci」を選ぶ点に注意してください。
下記を参考に、データベースの設定を「.env」ファイルに追記します。

```php:.env
 9行目 DB_CONNECTION=mysql
10行目 DB_HOST=127.0.0.1
11行目 DB_PORT=3306
12行目 DB_DATABASE=データベース名
13行目 DB_USERNAME=ユーザー名
14行目 DB_PASSWORD=パスワード
```

###Laravelの日本語化
[Laravel7を日本語化する方法](https://qiita.com/one_punch_man/items/7737559f12d579d313f9)
上記の記事を参考に、Laravelを日本語化します。

1.以下からZipファイルをダウンロードします。
https://github.com/caouecs/Laravel-lang

2.解凍したLaravel-lang-masterフォルダのjson/ja.jsonを、プロジェクトフォルダの resources/langに移動します。

3.Laravel-lang-master/src内のjaフォルダを、プロジェクト内のresources/langに移動します。最終的に下の画像になればOKです。
![202006241828.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/52c046b3-2e65-7bad-02b2-387bfb9c219f.png)


##[Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る①](https://note.com/mukae9/n/n12cc13fd4f90?magazine_key=mf7a8ea438ba1)

ここから基本的にエラーが起こった場所のみとコードが違う場合のみ書いていきます。

###１、まずは認証機能を作成します。
以下のコマンドを実行します。

```
$ cd ec_app
$ composer require laravel/ui --dev
$ php artisan ui vue --auth
$ npm install
$ npm run dev
```

###課題

```
$ php artisan make:migration create_carts_table     
```

上記コマンドを実行して、create_carts_tableを作成し、中身を以下のように変更します。

```database/migrations/2020_06_24_185504_create_carts_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCartsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('carts', function (Blueprint $table) {
            $table->id();
            $table->integer('stock_id');
            $table->integer('user_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('carts');
    }
}
```

下記のコマンドを実行して完了です。

```
$  php artisan migrate
```


##[Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る②](https://note.com/mukae9/n/naf7dff31b4db)
エラーはありませんでした。
###課題

```
$ php artisan make:migration create_mines_table   
```

上記コマンドを実行して、create_mines_tableを作成し、中身を以下のように変更します。

```database/migrations/2020_06_24_185504_create_carts_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateMinesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('mines', function (Blueprint $table) {
            $table->id();
            $table->string('name','50');
            $table->integer('age');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('mines');
    }
}
```

下記のコマンドを実行します。

```
$ php artisan migrate
$ php artisan make:seed MineTableSeeder
```

下記の２つのファイルを変更します。

```database/seeds/MineTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class MineTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('mines')->truncate(); //2回目実行の際にシーダー情報をクリア
        DB::table('mines')->insert([
            'name' => 'フィルムカメラ',
            'age' => 10,
        ]);
        DB::table('mines')->insert([
            'name' => 'イヤホン',
            'age' => 20,
        ]);
    }
}
```


```database/seeds/MineTableSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(MineTableSeeder::class);
    }
}
```

最後に下記のコマンドを実行すればOKです。

```
$ composer dump-autoload
$ php artisan db:seed
```

##[Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る③](https://note.com/mukae9/n/n2ed6be437f0d)

今回は何もエラーは起こりませんでしたので、記事通りにすすめてください。

###課題
課題も長くなるので省略しますが、下記のコマンドを実行しました。create_carts_tableは既に作成済みのため、省略しています。

```
$ php artisan make:model Models/Cart
```

下記のようにファイルを書き換えます。

```routes/web.php
//追記
Route::get('/mycart', 'ShopController@myCart');
```

```resources/views/mycart.blade.php
@extends('layouts.app')

@section('content')
<div class="container-fluid">
  <div class="">
    <div class="mx-auto" style="max-width:1200px">
      <h1 style="color:#555555; text-align:center; font-size:1.2em; padding:24px 0px; font-weight:bold;">商品一覧</h1>
      <div class="">
        <div class="d-flex flex-row flex-wrap">
          商品一覧を出したい<br>

          {{-- 追加 --}}

          @foreach($carts as $cart)
          {{$cart->user_id}} <br>
          {{$cart->stock_id}}<br>
          @endforeach

          {{-- ここまで --}}
        </div>
      </div>
    </div>
  </div>
</div>
@endsection
```

```app/Models/Cart.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Cart extends Model
{
    protected $guarded = [
        'stock_id',
        'user_id'
    ];
}
```

```app/Http/Controllers/ShopController.php
<?php

namespace App\Http\Controllers;

use App\Models\Stock;
use App\Models\Cart; //追加
use Illuminate\Http\Request;

class ShopController extends Controller
{
    public function index()
    {
        $stocks = Stock::Paginate(6);
        return view('shop',compact('stocks'));
    }
    
    public function myCart() //追加
    {
        $carts = Cart::all();
        return view('mycart',compact('carts'));
    }
}
```

###実践課題
下記のようにファイルを書き換えます。

```routes/web.php
// ログイン状態
Route::group(['middleware' => 'auth'], function() {
    Route::get('/mycart', 'ShopController@myCart');
});
```

##[Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る④](https://note.com/mukae9/n/n103587d08ef2)

前回の課題の答え合わせをして、相違点があったので修正しました。

###４、カートの中身を表示する
ここまで来たときに下記のエラーが出ました。
![202006281246.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/48220310-f634-f1d2-69b1-9c8663b74b0b.png)
エラーの内容を見ると、```user_id```が取得できていないため、エラーになっています。
まだ、userテーブルにはデータを未挿入なので、とりあえず下記のように「ShopController.php」を変更しました。

```app/Http/Controllers/ShopController.php
public function addMyCart(Request $request)
    {
        $user_id = 1; 
        $stock_id=$request->stock_id;
        $cart_add_info=Cart::firstOrCreate(['stock_id' => $stock_id,'user_id' => $user_id]);
        if($cart_add_info->wasRecentlyCreated){
            $message = 'カートに追加しました';
        }
        else{
            $message = 'カートに登録済みです';
        }
        $my_carts = Cart::where('user_id',$user_id)->get();
        return view('mycart',compact('my_carts' , 'message'));
}
```

すると、以下のようなエラーメッセージに変わりました。
![202006281303.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/cd6fdf2d-a61d-23e7-1bf8-b38821c46057.png)
まだログインしていないので、一旦「mycart.blade.php」ファイルを下記のように変更しました。

```resources/views/mycart.blade.php
@extends('layouts.app')

@section('content')
<div class="container-fluid">
  <div class="mx-auto" style="max-width:1200px">
    <h1 class="text-center font-weight-bold" style="color:#555555;  font-size:1.2em; padding:24px 0px;">

      <div class="">
        <p class="text-center">{{ $message }}</p><br>
        <div class="d-flex flex-row flex-wrap">

          @foreach($my_carts as $my_cart)
          <div class="mycart_box">
            <p>ユーザーID：{{$my_cart->user_id}}</p>
            <p>ストックID：{{$my_cart->stock_id}}</p>
            @endforeach

          </div>

          <a href="/">商品一覧へ</a>
        </div>
      </div>
  </div>
</div>
@endsection
```

これで記事通りに表示されました。

##[Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る⑤](https://note.com/mukae9/n/n18125664d380)

記事通りに進める前に、会員登録してUserを1つ作っておきます。
前回変更したファイルを、下記のように変更します。

```app/Http/Controllers/ShopController.php
<?php

namespace App\Http\Controllers;

use App\Models\Stock; //追加
use App\Models\Cart; //追加
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class ShopController extends Controller
{
    public function index() //追加
    {
        $stocks = Stock::Paginate(6); //Eloquantで検索
        return view('shop',compact('stocks')); //追記変更
    }
    
    public function myCart() //追加
    {
        $my_carts = Cart::all(); //Eloquantで検索
        return view('mycart',compact('my_carts')); //追記変更
    }

    public function addMyCart(Request $request)
    {
        $user_id = Auth::id(); 
        $stock_id=$request->stock_id;
        $cart_add_info=Cart::firstOrCreate(['stock_id' => $stock_id,'user_id' => $user_id]);
        if($cart_add_info->wasRecentlyCreated){
            $message = 'カートに追加しました';
        }
        else{
            $message = 'カートに登録済みです';
        }
        $my_carts = Cart::where('user_id',$user_id)->get();
        return view('mycart',compact('my_carts' , 'message'));
    }
}

```

```resources/views/mycart.blade.php
@extends('layouts.app')

@section('content')
<div class="container-fluid">
  <div class="mx-auto" style="max-width:1200px">
    <h1 class="text-center font-weight-bold" style="color:#555555;  font-size:1.2em; padding:24px 0px;">
    {{ Auth::user()->name }}さんのカートの中身</h1>

      <div class="">
        <p class="text-center">{{ $message ?? '' }}</p><br>
        <div class="d-flex flex-row flex-wrap">

          @foreach($my_carts as $my_cart)
          <div class="mycart_box">
            <p>ユーザーID：{{$my_cart->user_id}}</p>
            <p>ストックID：{{$my_cart->stock_id}}</p>
            @endforeach

          </div>

          <a href="/">商品一覧へ</a>
        </div>
      </div>
  </div>
</div>
@endsection
```

これで記事のとおりに進めてもエラーは起こりませんでした。
###課題
①「web.php」に以下を追記します。

```routes/web.php
Route::post('/cartdelete', 'ShopController@deleteCart');//追記
```

②③以下のようにファイルに追記します。

```app/Http/Controllers/ShopController.php
public function deleteCart(Request $request, Cart $cart)
{
        $stock_id=$request->stock_id;
        $user = auth()->user();
        $message = $cart->deleteMyCart($user->id, $stock_id);
        $my_carts = $cart->showCart();
        return view('mycart',compact('my_carts' , 'message'));
}
```

```app/Models/Cart.php
public function deleteMyCart(Int $stock_id, Int $user_id)
{
        $user_id = Auth::id(); 
        $this->where('user_id', $user_id)->where('stock_id', $stock_id)->delete();
        return $message = '商品をカート内から削除しました';
}
```

なんとなくは動きますが、上手く削除できなかったので、次に進んで答えを確認します。

##[Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る⑥](https://note.com/mukae9/n/na6c15b5f9cec?magazine_key=m1efe9a2b9813)

###１、課題の答え合わせ
この通りにすると、上手く動きました。

###６、購入完了のメールを送信する
ここで下記のエラーが出ました。
![202006281303.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/a4ff5e2a-8aa7-ee44-950c-f2e4f2b37731.png)
「ShopController.php」を下記のように書き換えました。

```
public function checkout(Cart $cart)
{
        $checkout_info = $cart->checkoutCart();
        Mail::to('test@example.com')->send(new Thanks); //追記
        return view('checkout');
}
```

キャッシュをクリアするために、下記のコマンドを実行し、エラーが解消しました。

```
$ php artisan config:cache
```

あとは記事通りに進めていけば、エラーは起こりませんでした。

##[TwitterAPI アカウント申請〜許可まで【2020年版】](https://note.com/mukae9/n/nb249bcfe6ee9)
Twitterログインを実装するためには、Twitter Apiを使用する許可が必要となるため、この記事を参考に申請しました。
数日かかるようですが、私の場合はすぐに使えるようになりました。
![202006282123.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/b300a6cc-28e0-0999-0f91-b3b29608aa8d.png)

##[Laravel6.0+SocialiteでTwitterログインを実装する](https://note.com/mukae9/n/n91ff7bccfcd8)

ここからは、個人的に始めてやることなので、記録として残していきます。

###１、とりあえず認証機能を追加
構築済みなので飛ばします。

###２、Socialiteをcomposerでダウンロード。
以下のコマンドを実行して、composerを利用してsocialite機能に必要なやつファイルを一気に取得します。

```
$ composer require laravel/socialite
```

###３、とりあえずルーティング
routes/web.phpにTwitterのためのルーティングを書きます。

```routes/web.php
Route::get('login/twitter', 'Auth\LoginController@redirectToTwitterProvider');
Route::get('login/twitter/callback', 'Auth\LoginController@handleTwitterProviderCallback');
```

###３、コントローラーに処理を記述する①
LoginController.phpに以下を追記します。

```app/http/Controllers/Auth/LoginController.php
public function redirectToTwitterProvider()
{
        return Socialite::driver('twitter')->redirect();
}
```

###４、使う前の下準備
Socialite::を使うためにサービスプロバイダへの登録とエイリアスの作成を行います。
config/app.phpの'providers' => []と'aliases' => []に以下を追記します。

```config/app.php
// providers
Laravel\Socialite\SocialiteServiceProvider::class,

//aliases
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
```

config/services.phpに以下を追記します。

```config/services.php
'twitter' => [
       'client_id' => env('TWITTER_CLIENT_ID'),
       'client_secret' => env('TWITTER_CLIENT_SECRET'),
       'redirect' => env('CALLBACK_URL')
],
```

.envに以下を追記します。


```php:.env
TWITTER_CLIENT_ID=************************* //下を参照
TWITTER_CLIENT_SECRET=************************* //下を参照
CALLBACK_URL=http://localhost/login/twitter/callback //よく見たらルーティングしたやつ
```

TWITTER_CLIENT_IDとTWITTER_CLIENT_SECRETは、下記のように取得します。

https://developer.twitter.com/en/apps
にアクセスして、「create app」をクリックします。
![202006282152.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/7a920940-f8a7-46a5-17bc-466d198bd721.png)
英語を入力していき、「create」をクリックします。
![202006282211.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/2ffbaaf1-8356-d44d-11b3-55242ba65bf4.png)
下記のモーダルウィンドウが出てくるので、「create」をクリックします。
![202006282211.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/3355b2e1-812a-9ae4-541e-aa9c21aeeecc.png)
下記のような画面に遷移するのでにpermissionsタブを開き、Additional premissionsにチェックが入っていないとEmail情報が取得できないので許可を出しておきます。
![202006282214.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/8d3297dd-10a2-0906-da89-b9fe90ef057e.png)
最後に「Keys and tokens」にタブを切変えると、APIが取得できます。
![202006282219.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/7bca6763-5116-a246-9bc0-5a09e6786b21.png)
「TWITTER_CLIENT_ID」に「API Key」を、「TWITTER_CLIENT_SECRET」に「API secret key」を入力します。

###５、コントローラーに処理を記述する②
Auth\LoginControllerにhandleTwitterProviderCallbackを実装します。以下を追記します。

```app/http/Controllers/Auth/LoginController.php
public function handleTwitterProviderCallback(){

       try {
           $user = Socialite::with("twitter")->user();
       } 
       catch (\Exception $e) {
           return redirect('/login')->with('oauth_error', 'ログインに失敗しました');
           // エラーならログイン画面へ転送
       }
       
       $myinfo = User::firstOrCreate(['token' => $user->token ],
                 ['name' => $user->nickname,'email' => $user->getEmail()]);
                 Auth::login($myinfo);
                 return redirect()->to('/'); // homeへ転送
    
}
```

database/migration/2014_10_12_000000_create_users_tableのupメソッドを以下のように変更します。

```database/migration/2014_10_12_000000_create_users_table.php
public function up()
   {
       Schema::create('users', function (Blueprint $table) {
           $table->bigIncrements('id');
           $table->string('name');
           $table->string('email')->unique();
           $table->timestamp('email_verified_at')->nullable();
           $table->string('password')->nullable(); //->nullabale();追加
           $table->string('token')->nullable();　//追加
           $table->rememberToken();
           $table->timestamps();
       });
}
```

app/User.phpを以下のように編集します。

```
protected $fillable = [
        'name', 'email', 'password', 'token',
];
```

後は以下のコマンドを順に実行します。

```
$ php artisan migrate:fresh --seed
$ composer dump-autoload
$ npm run dev
$ php artisan config:cache
$ php artisan serve
```

このままだとパスワードに問題があるとのことで、さらにうまくできずにエラーが起きて修正できなかったので、下記に進みます。

##[Laravel 6.5 と Socialite で Twitter OAuth ログインを実現する](https://econosys-system.com/blog/archives/419)

上記の記事を参考に以下の点を変更しました。

###5.Twitter Developersから Twitterアプリを登録します
https://dev.twitter.com/index
上記にアクセスして下記を変更しました。

```
Callback URL: http://あなたのサーバ名/auth/twitter/callback
```

同様に.envファイルも修正します。

```php:.env
TWITTER_CALLBACK_URL=http://あなたのサーバ名/auth/twitter/callback
```

###6.laravelのルーティングを設定
routes/web.php に以下を追加します。

```routes/web.php
// Auth Twitter
Route::get('auth/twitter', 'Auth\AuthController@TwitterRedirect');
Route::get('auth/twitter/callback', 'Auth\AuthController@TwitterCallback');
Route::get('auth/twitter/logout', 'Auth\AuthController@getLogout');

// Auth Google
Route::get('auth/google', 'Auth\AuthController@GoogleRedirect');
Route::get('auth/google/callback', 'Auth\AuthController@GoogleCallback');
Route::get('auth/google/logout', 'Auth\AuthController@getLogout');

// Auth Facebook
Route::get('auth/facebook', 'Auth\AuthController@FacebookRedirect');
Route::get('auth/facebook/callback', 'Auth\AuthController@FacebookCallback');
Route::get('auth/facebook/logout', 'Auth\AuthController@getLogout');
```

###7コントローラーの設定

app/Http/Controllers/Auth/AuthController.php を以下の内容で新規作成します。

```app/Http/Controllers/Auth/AuthController.php
<?php
namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Socialite;

class AuthController extends Controller
{

    public function TwitterRedirect()
    {
        return Socialite::driver('twitter')->redirect();
    }

    public function TwitterCallback()
    {
        // OAuthユーザー情報を取得
        $social_user = Socialite::driver('twitter')->user();
        $user = $this->first_or_create_social_user('twitter', $social_user->id, $social_user->name, $social_user->avatar );

        // Laravel 標準の Auth でログイン
        \Auth::login($user);

        return redirect('/home');
    }

    /**
     * ログインしたソーシャルアカウントがDBにあるかどうか調べます
     *
     * @param   string      $service_name       ( twitter , facebook ... )
     * @param   int         $social_id          ( 123456789 )
     * @param   string      $social_avatar      ( https://....... )
     *
     * @return  \App\User   $user
     *
     */
    protected function first_or_create_social_user( string $service_name,
                                                int $social_id, string $social_name, string $social_avatar )
    {
        $user = null;
        $user = \App\User::where( "{$service_name}_id", '=', $social_id )->first();
        if ( $user === null ){
            $user = new \App\User();
            $user->fill( [
                "{$service_name}_id" => $social_id ,
                'name'               => $social_name ,
                'avatar'             => $social_avatar ,
                'password'           => 'DUMMY_PASSWORD' ,
            ] );
            $user->save();
            return $user;
        }
        else{
            return $user;
        }
    }

}
```

###8.URLを叩いてログインをテストする
login.blade.phpに以下を追記します。

```resorces/views/auth/login.blade.php
          <div class="form-group row mt-3">
            <div class="col-md-6 offset-md-4">
              <a href="auth/twitter">
                <button type="button" class="btn btn-primary"><i class="fab fa-twitter"></i> Twitterアカウントでログインする</button>
              </a>
            </div>
          </div>
```

<a href="{{ route('auth.twitter') }}">ではエラーが起きたので、<a href="auth/twitter">に変更しています。

###9.実際のログイン後の実装（ユーザー自動作成）
2014_10_12_000000_create_users_table.phpのupメソッドをデフォルトに戻します。

```2014_10_12_000000_create_users_table.php
public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
```

以下のコマンドを実行します。

```
$ composer require doctrine/dbal
$ php artisan make:migration change_users_table_add_oauth_columns  --table=users
```

change_users_table_add_oauth_columns.php を編集します。

```2020_06_28_234825_change_users_table_add_oauth_columns.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ChangeUsersTableAddOauthColumns extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->datetime('avatar')->nullable()->after('remember_token')->comment('アバター画像');
            $table->unsignedBigInteger('twitter_id')->nullable()->after('remember_token')->comment('Twitter ID');
            $table->unsignedBigInteger('facebook_id')->nullable()->after('remember_token')->comment('Facebook ID');
            $table->unsignedBigInteger('github_id')->nullable()->after('remember_token')->comment('GitHub ID');
            $table->unsignedBigInteger('google_id')->nullable()->after('remember_token')->comment('Google ID');
            $table->unsignedBigInteger('yahoo_id')->nullable()->after('remember_token')->comment('Yahoo ID');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('avatar');
            $table->dropColumn('twitter_id');
            $table->dropColumn('facebook_id');
            $table->dropColumn('github_id');
            $table->dropColumn('google_id');
            $table->dropColumn('yahoo_id');
        });
    }
}
```

app\User.phpを編集します。

```app\Users.php
    // protected $fillable = [
    // 'name', 'email', 'password', 'token',
    // ];
    
    // guarded
    protected $guarded = ['id', 'created_at', 'updated_at'];
```

DatabaseSeeder.php　を変更します。

```DatabaseSeeder.php
    public function run()
    {
        $this->call(MineTableSeeder::class)
              ->call(StockTableSeeder::class);
    }
```

後は以下のコマンドを順に実行します。

###前項「Laravel6.0+SocialiteでTwitterログインを実装する」の項目を戻す

config/app.phpに追加した項目をコメントアウトします。

```config/app.php
'providers'
        //これ追加！！
        //Laravel\Socialite\SocialiteServiceProvider::class,

'aliases'
        // 以下を追記
        //'Socialite' => Laravel\Socialite\Facades\Socialite::class,
```

LoginControllerも戻します。

```Auth\LoginController.php
//    public function redirectToTwitterProvider()
//    {
//        return Socialite::driver('twitter')->redirect();
//    }
//
//    public function handleTwitterProviderCallback(){
//
//        try {
//            $user = Socialite::with("twitter")->user();
//        } 
//        catch (\Exception $e) {
//            return redirect('/login')->with('oauth_error', 'ログインに失敗しました');
//            // エラーならログイン画面へ転送
//        }
//
//        $myinfo = User::firstOrCreate(['token' => $user->token ],
//                  ['name' => $user->nickname,'email' => $user->getEmail()]);
//                  Auth::login($myinfo);
//                  return redirect()->to('/'); // homeへ転送
//    }
```

###まだエラーが起きたので、下記を修正
Twitter関連は絵文字を使うので、使えるように修正します。

```config/database.php
'mysql' => [
		'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_general_ci',		
],
```

データベースはphpMyAdminでDBを選択し、「操作」→「照合順序」でか下記のように「utf8mb4_general_ci」に変更します。
![202006290054.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643170/b371acf9-5de6-fb8b-4305-06e9daa31528.png)
画像のURLをtimestamp型に受け取るになっていたので修正します。

```2020_06_28_234825_change_users_table_add_oauth_columns.php
// 変更前
$table->timestamp('avatar')->nullable()->after('remember_token')->comment('アバター画像');

// 変更後
$table->string('avatar')->nullable()->after('remember_token')->comment('アバター画像');
```

※上記３つが終わったら、一度「$ php artisan migrate:fresh --seed」しないとエラーになるので注意。

Emailを入力していなかったので追加しました。ついでにリダイレクト先も変更しています。

```AuthController.php
<?php
namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Socialite;
use App\Models\User;

class AuthController extends Controller
{

    public function TwitterRedirect()
    {
        return Socialite::driver('twitter')->redirect();
    }

    public function TwitterCallback()
    {
        // OAuthユーザー情報を取得
        $social_user = Socialite::driver('twitter')->user();
        $user = $this->first_or_create_social_user('twitter', $social_user->id, $social_user->name, $social_user->email, $social_user->avatar );

        // Laravel 標準の Auth でログイン
        \Auth::login($user);

        return redirect('/');
    }

    /**
     * ログインしたソーシャルアカウントがDBにあるかどうか調べます
     *
     * @param   string      $service_name       ( twitter , facebook ... )
     * @param   int         $social_id          ( 123456789 )
     * @param   string      $social_avatar      ( https://....... )
     *
     * @return  User   $user
     *
     */
    protected function first_or_create_social_user( string $service_name,
                                                int $social_id, string $social_name, string $social_email, string $social_avatar )
    {
        $user = null;
        $user = User::where( "{$service_name}_id", '=', $social_id )->first();
        if ( $user === null ){
            $user = new User();
            $user->fill( [
                "{$service_name}_id" => $social_id ,
                'name'               => $social_name ,
                'email'               => $social_email ,
                'avatar'             => $social_avatar ,
                'password'           => 'DUMMY_PASSWORD' ,
            ] );
            $user->save();
            return $user;
        }
        else{
            return $user;
        }
    }
}
```

最後に下記のコマンドを実行します。

```
$ php artisan migrate:fresh --seed
$ composer dump-autoload
$ npm run dev
$ php artisan config:cache
$ php artisan serve
```

これでTwitterでログインできるようになりました。
ソースコードはhttps://github.com/neneta0921/ec_app にて公開しているので、宜しけば参考にしてください。
長くなりましたが、以上です。