4
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at

引用:【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');
    }


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

引用:公式ドキュメント(多対多)
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で取得できるようにしておきましょう。
これら2つを使ってインスタンスを生成

 $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>

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

4
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?