🙌

【Laravel 10】belongsToManyで中間テーブルのリレーションを設定する

2024/03/04に公開

少しテーブルが多くなってくるとすぐに出てくるのが中間テーブルを介してのデータの保存・変更・削除・検索です。

分かりにくいためLaravelでの設定を備忘録として書いておきます。

テーブルの関係

モデル テーブル 状態
Articleモデル articlesテーブル
Tagモデル tagsテーブル
ArticleTagモデル article_tagsテーブル 中間テーブル

belongsToMany とは?

リレーションの定義でよく使用するのがこのメソッド。
Laravel Eloquent ORM のメソッドです。
belongsToManyの公式ドキュメントはこちら

リレーションはどちらのモデルに定義する?

リレーションは通常、両方のモデルに定義します。
場合によっては片方でもありですが拡張性を考えると両方に定義しておくのがベターです。

belongsToMany('多対多の相手側のクラス名…ClassName::class',
'中間テーブルの名前', '中間テーブル外部キー名', '中間テーブル外部キー名')

ちなみに第2引数に中間テーブル名を指定しなかった場合、2つのモデル名の単数形をアルファベット順に結合した名前であるという前提で処理されます。

第3引数、第4引数は中間テーブルカラム名【リレーション元・先のテーブル名の単数形_id】という規則性に当てはまらない時に指定します。

第3引数、第4引数の指定について

ArticleモデルのArticle.phpにコードを記載して定義しているとします。

第3引数
記載しているファイル、つまりArticleモデル(articlesテーブル)のidと、ここに記入したカラム名にリレーションの設定が行われます

第4引数
もう1つのモデルのidと、ここに記入したカラム名にリレーションの設定が行われます

Articleモデルに定義

class Article extends Model
{
    public function tags()
    {
        return $this->belongsToMany(Tag::class, 'article_tags', 'article_id', 'tag_id');
    }
}

Tag::class
Tagモデルとリレーションを定義します。

article_tags
article_tagsを中間テーブルとして定義します

article_id
article_tagsテーブルの中のarticle_idは、Articleモデル(articlesテーブル)のidカラムと紐づけられます

tag_id
article_tagsテーブルの中のtag_idは、Tagモデル(tagsテーブル)のidカラムと紐づけられます

ClassName::class とは何なのか?
名前空間を文字列として返しています
[例]Tag::class
上記記述では、App\Model\Tag を文字列として返します

Tagモデルに定義

class Tag extends Model
{
    public function articles()
    {
        return $this->belongsToMany(Article::class, 'article_tags', 'tag_id', 'article_id' );
    }
}

コントローラーのメソッドで呼び出す

これで中間テーブルのリレーションの定義は完了しました。
あとは、各メソッドで中間テーブルが関係するメソッドを作成していきましょう。

// ArticleController.php

class ArticleController extends Controller{
// タグの保存
        foreach ($data['tagList'] as $tag) {
            $tagModel = Tag::firstOrCreate(['name' => $tag]); // 既存のタグがあればそれを取得、なければ新規作成
            $article->tags()->attach($tagModel->id);
        }
}

article->tags()->attach(tagModel->id);
ここでリレーションの定義を使って中間テーブルにデータを挿入しています。

$article->tags()
tags()はArticlesモデルに定義したtags()メソッドのことです。
Articleモデルとリレーション(tags()メソッド)を関連づけています。

attach
attachメソッドを使用してリレーションの中間テーブルへレコードを挿入します。

$tagModel->id
$tagModel …
挿入するデータを第1引数に記入します。
$tagModelはすぐ上で定義された変数で、新しく保存したいタグの情報です。

$id …
$tagModelのidプロパティを参照しています。
idはそのモデルの主キーを表しています。

特に最後のメソッドでの使用が分かりにくいので今後の課題としておきます。

Discussion