現在、教材を見ながらTwitterのクローンアプリを作っています。フォロー機能のコード手順メモです。
手順1: まず、以下がフォローリストのViewコード。アバター部分はまだハードコーディング。
<h3 class="font-bold text-lg mb-4">フォローリスト</h3>
<ul>
@foreach (auth()->user()->follows as $user)
<li class="mb-4">
<div class="flex items-center text-sm">
<img src="/images/avator.png" alt="" class="rounded-full mr-2 w-10">
{{ $user->name }}
</div>
</li>
@endforeach
</ul>
手順2: @foreach (auth()->user()->follows as $user)
の部分で使っている、followsのリレーションを設定します。
ユーザーは沢山の他のユーザーをフォローすることができるから、リレーションはbelongsToMany()にします。このリレーションで、どのユーザーがどのユーザをフォローしているのかを管理できます。
public function follows() {
return $this->belongsToMany(User::class);
}
手順3: pivotテーブルとなるfollowsテーブルを作成します。
php artisan make:migration create_follows_table
手順4: マイグレーションファイルを設定します。
ユーザー間及びフォローしているユーザー間の関係を設定する為には、'user_id' と、'following_user_id' が必要になります。
$table->primary(['user_id', 'following_user_id']);
の部分で二つプライマリーキーを指定しているのは、ユーザーがボタンを二度押しとかした時に重複を許さないようにする為。
public function up()
{
Schema::create('follows', function (Blueprint $table) {
$table->primary(['user_id', 'following_user_id']);
$table->foreignId('user_id');
$table->foreignId('following_user_id');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->foreign('following_user_id')
->references('id')
->on('users')
->onDelete('cascade');
});
}
手順5: マイグレーションします。
php artisan migrate
手順6: 取り敢えず、followsテーブルに手動でデータを入れてみます。
手順7: これからtinkerで確認作業をしていくのですが、その前にUserモデルを以下のように修正しておきます。
'follows'とするのは、Laravelでは慣習的にpivotテーブルの名前は、双方のテーブル名をアルファベット順にアンダーバーでつなげる為です。今回の場合だと『user_user』というファイル名をLaravelが認識するのですが、そうではなくてfollowsだよ、と伝える為です。また、カスタムしたカラムネームを使っている為、foreignPivotKeyとrelatedPivotKeyを明示します。(PivotテーブルでLaravelが認識するデフォルトのカラムネームは、『モデル名_id』です。これと異なる場合は、明示する必要があります。今回の場合だと、foreignPivotKeyとrelatedPivotKeyの両方ともuser_id。)
public function follows() {
return $this->belongsToMany(User::class, 'follows', 'user_id', 'following_user_id');
}
手順8: tinkerを立ち上げて確認してみます。
php artisan tinker
App\Models\User::find(1)->follows;
Userモデルのインスタンスが返されて、以下のように表示されます。Userモデルのid1のユーザーがフォローしている、id3と5のユーザーが出てきます。
>>> App\Models\User::find(1)->follows;
=> Illuminate\Database\Eloquent\Collection {#3772
all: [
App\Models\User {#4389
id: 3,
name: "原田 里佳",
email: "sugiyama.taichi@example.com",
email_verified_at: "2020-10-06 12:13:24",
current_team_id: null,
profile_photo_path: null,
created_at: "2020-10-06 12:13:24",
updated_at: "2020-10-06 12:13:24",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4177
user_id: 1,
following_user_id: 3,
},
},
App\Models\User {#4140
id: 5,
name: "宮沢 充",
email: "ryohei11@example.com",
email_verified_at: "2020-10-06 12:13:24",
current_team_id: null,
profile_photo_path: null,
created_at: "2020-10-06 12:13:24",
updated_at: "2020-10-06 12:13:24",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4333
user_id: 1,
following_user_id: 5,
},
},
],
}
id3のユーザを検索して見てみると。。。
App\Models\User::find(3)->follows;
何も出てこないのでOKです。
=> Illuminate\Database\Eloquent\Collection {#4394
all: [],
手順9: リレーション設定したものを、データベースに保存する関数を作ります。
public function follow(User $user) { // ←この関数追記
return $this->follows()->save($user);
}
public function follows() {
return $this->belongsToMany(User::class, 'follows', 'user_id', 'following_user_id');
}
手順10: 上記で作ったfollow()関数を、tinkerで確認していくのですが、その前にデータをリフレッシュしておきます。
php artisan migrate:fresh
手順11: 新たにuserテーブルにデータを入れていきます。このような感じ。(id1だけはブラウザのregisterページから手動で登録して、その他はFactory機能で登録しました。)
手順12: tinkerでフォローの設定・確認をしていきます。
id1(ログインしている自分のid)が、id3とid5をフォローしていて、id3とid5がそれぞれid1をフォローしている、という設定をしてみます。(相互フォロー)
follow()関数に渡すのは、ユーザーモデルのインスタンスでなければいけないので、それぞれのidを探して、変数に格納します。
$me = App\Models\User::find(1);
$taichi = App\Models\User::find(3);
$yoko = App\Models\User::find(5);
手順13: follow()関数を使って、それぞれがフォローするようにテーブルに登録します。
$me->follow($taichi);
$me->follow($yoko);
$taichi->follow($me);
$yoko->follow($me);
テーブルには以下のように入ります。
ブラウザで確認(id1のアカウント)すると、ちゃんと表示もされています。
手順14: id1がid6をフォローしてみます。
$yumiko = App\Models\User::find(6);
$me->follow($yumiko);
手順15: id1がフォローしている全idを確認してみると、以下のように出ます。
$me->follows;
=> Illuminate\Database\Eloquent\Collection {#4390
all: [
App\Models\User {#4391
id: 3,
name: "若松 太一",
email: "manabu.saito@example.com",
email_verified_at: "2020-10-06 17:02:31",
current_team_id: null,
profile_photo_path: null,
created_at: "2020-10-06 17:02:31",
updated_at: "2020-10-06 17:02:31",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4394
user_id: 1,
following_user_id: 3,
},
},
App\Models\User {#4392
id: 5,
name: "喜嶋 陽子",
email: "minoru89@example.org",
email_verified_at: "2020-10-06 17:02:31",
current_team_id: null,
profile_photo_path: null,
created_at: "2020-10-06 17:02:31",
updated_at: "2020-10-06 17:02:31",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4333
user_id: 1,
following_user_id: 5,
},
},
App\Models\User {#4395
id: 6,
name: "中津川 裕美子",
email: "lkimura@example.com",
email_verified_at: "2020-10-06 17:02:31",
current_team_id: null,
profile_photo_path: null,
created_at: "2020-10-06 17:02:31",
updated_at: "2020-10-06 17:02:31",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3457
user_id: 1,
following_user_id: 6,
},
},
],
}
以上です。