Commentはじめに皆さんこんにちは。Laravelの多対多のリレーションについて、曖昧な部分が多かったので勉強がてら基本的な部分を整理してみました。多対多には中間テーブルとbelongsToMany()を使う例えば「ブログ記事」とそれに対する「タグ」の場合のように、それぞれのブログ記事は複数のタグを持ち、それぞれのタグも同様に複数のブログを持ち得るような場合で、中間テーブルが必要になるケースです。Laravelにおけるこのような多対多の関係は、belongsToMany()を使って定義されることになります。belongsToMany()を使って定義した多対多のリレーションの場合、attach()/detach()/sync()などのメソッドを利用することができます。サンプルを使ってコンソールでそれらのメソッドを確認する方法も記載しましたので、参考にしてみてください。ちなみにhasManyThrough()を使っても例えばブログ記事から紐づくタグを取得するというようなことは可能なようですが、hasManyThrough()は3つのテーブルが介するケースに対するショートカットのようなものに過ぎないようなので、多対多のケースに関してはbelongsToMany()を使うことが適切なようです。(参考までにですが、こちらにサンプルコードがあります)belongsToMany()の使い方のサンプルここではArticle(ブログ記事)とTag(タグ)という2つのモデルについて、hasManyThrough()を使って多対多の関係を定義してコンソールで確認できるようになるまでのサンプルをまとめました。このようなケースではarticlesとtagsとarticle_tagの3つのテーブルが必要になります。中間テーブルに関してですが、関連するモデル名をアルファベット順で並べたarticle_tagという名前になり、article_idとtag_idというカラムが必要になります。(独自のテーブル名を用いることも可能ですが、その場合はhasManyThrough()の定義の際にテーブル名などの記述も必要になります。)マイグレーションファイルと各モデルの作成まずはブArticle(ブログ記事)とTag(タグ)という2つのモデルを作成し、同時にマイグレーションファイルも作成(-mオプションを使う)します。-m次に中間テーブルのマイグレーションファイルを作成します。中間テーブルに関しては独自のメソッド等必要なければモデルの定義は不要です。先述したように、テーブル名は関連するモデル名をアルファベット順で並べたarticle_tagという名前になり、article_idとtag_idというカラムが必要になります。--create=article_tagArticleのマイグレーションファイルにはbody(本文)というカラムを追加しておきます。}Tagのマイグレーションファイルにはname(タグの名前)というカラムを追加しておきます。}中間テーブルのマイグレーションファイルにはArticleとTagの外部キーをそれぞれ追加する必要があります。}テーブルの定義が終わったので、マイグレーションを実行します。migrate多対多のリレーションを各モデルに定義する最後にArticleとTagのモデルにそれぞれbelongsToMany()を使って多対多の定義を追加します。}}多対多のリレーションをコンソールで確認してみる最後にコンソール(tinker)からリレーションが正しく定義されているかどうかを確認してみます。tinkerArticleとTagのテストデータをまずは投入しておきます。ここではArticleを一つとTagを3つ投入しました。新たに紐づけするにはattach()を使うbelongsToMany()で定義したtags()から、attach()というメソッドを使って紐づけ対象のidを引数にしてリレーションを紐付けることができます。中間テーブルにレコードが自動的に挿入されます。紐づけられたTagを取得することができました。}紐づけを解除するにはdetach()を使うdetach()というメソッドはattach()の逆で、ヒモ付の解除をすることができます。中間テーブルのレコードが自動的に削除されます。各モデルのレコードには影響がありません。id=1のTagの紐付けを解除する以下のように、detach()したことで紐付けられたTagが削除されたことが確認できました。}まとめての紐づけと紐づけの解除を行うsync()他にもsync()という便利なメソッドがあります。紐づけるidのリストを引数として渡すことで、まとめて紐づけを行い、かつリストにないidは全て自動的に削除することができます。こちらも同様に中間テーブルのレコードの追加・削除が自動的に行われ、各モデルのレコードには影響がありません。id=1とid=2のTagを紐づけ、これ以外のものは紐づけを解除する以下のように、まとめて紐づけされたTagを取得することができました。}おまけ:hasManyThrough()を使って紐付いたタグを取得する本来は多対多の関係に関しては上に書いてきたようにbelongsToMany()を使って定義するべきなのですが、紐付いたタグの取得という部分に関しては、3つの関連するテーブルのリレーションということでhasManyThroughでも取得は可能なようでした。hasManyThroughは取得の際のショートカットのようなものに過ぎないようなのでこの場合は当然attach/detach/syncなどのメソッドは使うことはできません。多対多のリレーションに関しては常にbelongsToMany()で定義するべきなようです。参考ですが、上のサンプルに以下のような修正を行うことでhasManyThrough()でもArticleに紐づくTagを取得することができます。中間テーブルのモデルArticleTagのモデルを定義するファイルを作成し、テーブル名を定義します。テーブル名を定義する。}ArticleのTagとのリレーションをhasManyThrough()で定義するように修正します。ドキュメントにあるような形のリレーションとは異なるのでローカルキーや外部キーの指定の仕方が若干トリッキーです・・。紐付けられたタグが取得できる。このように、hasManyThrough()で定義したリレーションを使って紐付けられたタグを取得することが可能です。紐づけや紐づけの削除を行うには手動で中間テーブルのレコードをの追加・削除を行う必要があるので、多対多の関係にはドキュメント通りにbelongsToMany()を使いましょう!優秀な技術者と一緒に、好きな場所で働きませんか株式会社もばらぶでは、優秀で意欲に溢れる方を常に求めています。働く場所は自由、働く時間も柔軟に選択可能です。現在、以下の職種を募集中です。ご興味のある方は、リンク先をご参照下さい。採用情報プロジェクトマネージャー(リモート)ソフトウェアエンジニア(リモート)デザイナー(リモート)Subscriptionメールアドレスを記入して購読すれば、更新をメールで受信できます。ThemePacific。