laravelでフォロー機能を作成（多対多のリレーション）

引用：【Laravel + Vue.js講座】いいね機能を作ろう!! part1 - 【質問回答は無料】
https://www.youtube.com/watch?v=MJtQrsLrtJQ

こちらの動画を参考にいいね機能を作成したとき、これを応用すればフォロー機能も作成できるのではないかと考え作成

環境
PHP 7.3.11
Laravel Framework 7.29.3

## マイグレーション

```****_**_**_******_create_follow_users_table.php

 Schema::create('follow_users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('followed_user_id')->index();
            $table->unsignedBigInteger('following_user_id')->index();
            $table->foreign('followed_user_id')->references('id')->on('users')->onDelete('cascade');
            $table->foreign('following_user_id')->references('id')->on('users')->onDelete('cascade');
            $table->timestamps();
        });

```
followed_user_id:フォローされたユーザー（フォロワー）のID
following_user_id:フォローしたユーザーのID
両方ともusersテーブルのIDに結合する

##モデル

```FollowUser.php

class FollowUser extends Pivot
{
    protected $fillable = ['following_user_id', 'followed_user_id'];

    protected $table = 'follow_users';
    
}

```
多対多のリレーションを取る際の中間テーブルの名前はそれぞれのテーブル名の単数形同士を使うのがセオリーなんだけど今回はuser_userになって分かり辛いのでfollow_usersというテーブル名で作成
protected $table = 'follow_users';でテーブル名を定義

```User.php

 // フォロワー→フォロー
    public function followUsers()
    {
        return $this->belongsToMany('App\User', 'follow_users', 'followed_user_id', 'following_user_id');
    }

    // フォロー→フォロワー
    public function follows()
    {
        return $this->belongsToMany('App\User', 'follow_users', 'following_user_id', 'followed_user_id');
    }


```
１対多とかなら第一引数にリレーション先のモデル名を書くだけで済むのですが今回はオリジナルのテーブル名や多対多のリレーションを貼っていることもあり第四引数まで定義しているため少しややこしくなっています

引用：公式ドキュメント（多対多）
https://readouble.com/laravel/7.x/ja/eloquent-relationships.html#many-to-many

第一引数には使用するモデル
第二引数には使用するテーブル名
第三引数にはリレーションを定義しているモデルの外部キー名
第四引数には結合するモデルの外部キー名

第三、第四引数が少し分かり辛いけど取得したい情報を第三引数、あまりものを第四引数に置くって感じで認識してます。

そのためフォローしているユーザーを取得したいときはfollows（）
フォロワーを取得したいときはfollowUsers（）を使うって感じですね。

##コントローラー

```FollowUserController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;
use App\FollowUser;

class FollowUserController extends Controller
{
    public function follow(User $user) {
        $follow = FollowUser::create([
            'following_user_id' => \Auth::user()->id,
            'followed_user_id' => $user->id,
        ]);
        $followCount = count(FollowUser::where('followed_user_id', $user->id)->get());
        return response()->json(['followCount' => $followCount]);
    }

    public function unfollow(User $user) {
        $follow = FollowUser::where('following_user_id', \Auth::user()->id)->where('followed_user_id', $user->id)->first();
        $follow->delete();
        $followCount = count(FollowUser::where('followed_user_id', $user->id)->get());

        return response()->json(['followCount' => $followCount]);
    }
}


```
followはフォロー機能

```
'following_user_id' => \Auth::user()->id
```

フォローするのは当然自分なので認証ユーザー＝フォローユーザー

```
 'followed_user_id' => $user->id
```

暗黙の結合などを使ってフォローされる相手のIDを$user->idで取得できるようにしておきましょう。
これら２つを使ってインスタンスを生成

```
 $followCount = count(FollowUser::where('followed_user_id', $user->id)->get());
```
フォローされているユーザーの数をcountして取得

unfollowはFollowUserインスタンスを取得して削除する機能




##ルーティング

```web.php

Route::post('/users/{user}/follow', 'FollowUserController@follow');
Route::post('/users/{user}/unfollow', 'FollowUserController@unfollow');

```

FollowUserController@followでフォロー、unfollowでフォロー解除

##bladeファイル

```hoge.blade.php

<follow-component
:user-id = "{{ json_encode($user->id) }}"
:default-Followed = "{{ json_encode($defaultFollowed) }}"
:default-Count = "{{ json_encode($defaultCount) }}"
></follow-component>

```
$user->id（そのまんま$user_id）
$defaultFollowed(既にフォローしているかどうかをtrue,falseで返す)
$defaultCount（ユーザーのフォロー数を数えるための変数）


##vueファイル

```FollowComponent.vue

<template>
    <span class="float-right">
      <button v-if="!followed" type="button" class="btn-sm shadow-none border border-primary p-2" @click="follow(userId)"><i class="mr-1 fas fa-user-plus"></i>フォロー</button>
      <button  v-else type="button" class="btn-sm shadow-none border border-primary p-2 bg-primary text-white" @click="unfollow(userId)"><i class="mr-1 fas fa-user-check"></i>フォロー中</button>
    </span>
</template>

<script>
    export default {
        props:['userId', 'defaultFollowed', 'defaultCount'],
        data() {
          return{
              followed: false,
              followCount: 0,
          };
        },
        created() {
          this.followed = this.defaultFollowed
          this.followCount = this.defaultCount
        },

        methods: {
          follow(userId) {
            let url = `/users/${userId}/follow`

            axios.post(url)
            .then(response => {
                this.followed = true;
                this.followCount = response.data.followCount;
            })
            .catch(error => {
              alert(error)
            });
          },
          unfollow(userId) {
            let url = `/users/${userId}/unfollow`

            axios.post(url)
            .then(response => {
                this.followed = false;
                this.followCount = response.data.followCount;
            })
            .catch(error => {
              alert(error)
            });
          }
        }
    }
</script>

```
ほぼ本家様の受け売り
フォローしているかどうかでボタンの表示とメソッドを切り替えます