Laravelで多対多のリレーションをして保存、表示する方法【belongsToMany】
いつもご利用ありがとうございます。
この記事には広告が掲載されており、その広告費によって運営しています。
この記事では、Laravel で多対多のリレーションをモデルに定義すること。多対多の中間テーブルにデ ータを保存する方法、多対多のデータを表示する方法について書いていきます。
リレーションとは?
データベースのテーブル間で関係性のあるデータのことを指します。
今回の例で言えば、user_id を保存しておけば、users テーブルから user データを参照することができるようなことです。
Laravel では、少しの定義でこれを簡単に実装することができます。
検証環境
Laravel 6
テーブル設計
posts テーブルと、tags テーブルがあって、posts に紐づく tags が複数あるケースの話になります。
簡単にいうと、「ハッシュタグを複数つけられるようにしたい」ってことです。
そういう時には、多対多のリレーションを使う必要があります。
多対多には中間テーブルが必要
中間テーブルというのは、今回の画像でいうところの、
post_tag テーブルに当たります。
中間テーブル名は、単数系_単数系じゃないとダメ
まず、中間テーブルとして紐づけたいテーブルとテーブルの単数系をアンダーバーでつなぐ必要があります。
posts と tags テーブルの中間テーブルなので、post_tag となります。
中間テーブル名は、a-z 順で早い方が左側にこないとダメ
a-z 順という書き方をしてしまいましたが、abcd 順という意味です。
今回は、posts の p が、tags の t より abcd 順で先に来るので、post_tag というテーブル名になります。
users と tags の中間テーブルなら、t の方が u より先に来るので、tag_user になります。
モデルに定義する
中間テーブル用のモデルは不要です。
その代わり、Posts テーブルのモデルと、Tags テーブルのモデルの2つに記述する必要があります。
モデル Post.php
public function tags()
{
return $this->belongsToMany('App\Tag');
}
モデル Tag.php
public function posts()
{
return $this->belongsToMany('App\Post');
}
App\Post のところはモデルがあるところを定義してあげてください(App\Models\Post の人もいると思います。)
リレーションしたデータを取り出す方法
Post の一覧に複数タグをリレーションさせるためには、with を使うと良いです。
Controller
use App\Post;
~~~~~~~~
public function index()
{
$posts = Post::with('tags')->get();
//dd($posts);
return view('home');
}
次は、表示です。
タグは複数あるはずなので foreach で回してあげます。
views
@foreach($posts as $post)
{{ $post->title }}
@foreach($post->tags as $tag)
{{ $tag->name }}
@endforeach
@endforeach
保存する方法
$post に対して、タグを紐づけるときの書き方です。
注意して欲しいのは、新しいタグを生成するのと、タグを紐づけるのは別であることです。
新しいタグを新規作成しながら、タグを紐づける
新しいタグを作るときは、普通に new して save すれば作ることができます。その、作った ID を attach すればタグを紐づけることができます。
public function tag(Request $request)
{
//新しいタグを生成する場合
$tag = new Tag;
$tag->name = $request->name;
$tag->save();
//新しいポストの作成(findして既存のpostに紐づけるでもOK)
$post = new Post;
$post->user_id = 1;
$post->title = 'title';
$post->content = 'content';
$post->save();
//タグを紐づける(引数にタグのIDさえ渡れば良い)
//tags()はPostモデルで作ったfunctionの名前
//新しくタグを生成していたら、こんな感じ。
$post->tags()->attach($tag->id);
}
既存のタグを、新規の Post に紐づける
public function tag(Request $request)
{
//新しいタグを生成しない場合、tagのidだけrequestして送っても良いです。
$tag_id = $request->tag_id;
//新しいポストの作成(findして既存のpostに紐づけるでもOK)
$post = new Post;
$post->user_id = 1;
$post->title = 'title';
$post->content = 'content';
$post->save();
//既存のタグのIDだけ送ったパターン。
$post->tags()->attach($tag_id);
}
大事なのは、
$post->attach($tag->id);
この部分です。
すでにモデルでリレーションを定義していれば、これだけの記述で中間テーブルにデータが作成されます。
中間テーブルの削除
attach と同様に、detach という記述で簡単に済みます。
//狙った1つのタグだけを外したい
$post->detach($tag_id);
//postに紐づく全ての中間テーブルを削除したい
$post->detach();
となります。
まとめ
以上です。
多対多のリレーションについて、僕なりにわかりやすくまとめた記事となります。
中間テーブルの設計など、ちょっとややこしいところだと思いますが、できるだけ簡潔に書いてみました。
感想や誤字などありましたら、TwitterDM からご連絡お願いします。
人気記事
PHP7.4 + Laravel6 のプロジェクトを AWS EC2 にデプロイする
関連記事
Laravel で1対多のリレーションをして保存、表示する方法【hasMany】
Laravel で多対1のリレーションをして保存、表示する方法【belongsTo】