Skip to main content

カスタムピボットモデルとは

belongsToMany(多対多)の中間テーブルは、デフォルトでは素の Illuminate\Database\Eloquent\Relations\Pivot インスタンスとして扱われます。中間テーブルに追加のカラム(承認日時、ロールの種類など)を持たせたり、アクセサ・ミューテタ・独自メソッドを追加したりしたい場合は、Pivot を継承したカスタムモデルを作成します。
belongsToMany の定義で using() を呼び出し、このカスタムモデルを使うようリレーションに伝えます。
カスタムピボットモデルを保存するときは、モデル名を必ずアルファベット順の単数形で命名してください(RoleUser であって UserRole ではありません)。ただしこれは表示名の慣習であり、実際のクラス名は自由に決められます。

as()で取得したい属性を指定する

デフォルトでは中間テーブルの値は pivot プロパティ経由でアクセスします。as() メソッドを使うと、この名前を変更できます。

追加カラムとタイムスタンプ

中間テーブルに approved のような追加カラムがある場合は withPivot() で明示的に取得対象に含めます。created_at / updated_at を管理する場合は withTimestamps() を呼び出します。
Eloquentが中間テーブルの updated_at を自動更新するのは、そのピボットモデルが using() で明示的に指定されている場合のみです。デフォルトの Pivot クラスをそのまま使う場合でも withTimestamps() は動作しますが、using() でカスタムモデルを指定するとカスタムイベント・カスタムキャストなどが利用できるようになります。

ピボットモデルからの逆参照

カスタムピボットモデルには、宣言元モデル・関連先モデルへの belongsTo リレーションを自由に定義できます。
これにより、ピボットモデル単体を取得した場合でも $roleUser->role$roleUser->user で関連モデルにアクセスできます。ただし、これらのリレーションを親クエリ実行時に自動的にEagerロードしたい場合は、以下の chaperone() を使う方法があります。

chaperone()による自動Eagerロード(Laravel 13)

Laravel 13で、ピボットモデルに定義した role() / user() のような belongsTo リレーションを、belongsToMany クエリの実行時に自動でハイドレート(Eagerロード相当の紐付け)できる chaperone() メソッドが追加されました。
chaperone() を呼び出すと、Eloquentはピボットモデル(RoleUser)が持つ belongsTo リレーションの名前を自動的に推測し、Role::with('users') のようにコレクションを取得した際、各ピボットに紐づく宣言元モデル・関連先モデルへの参照を追加のクエリなしで設定します。

非標準なリレーション名を使う場合

ピボットモデルの belongsTo リレーションのメソッド名が標準的な命名(宣言元・関連先モデル名のキャメルケース単数形)と異なる場合は、chaperone() の引数で明示的に指定します。
chaperone() は「N+1問題」を中間テーブル経由の参照についても解消してくれる仕組みです。ピボットモデルから親モデルの情報(承認日時とユーザー名を一緒に表示する、など)を頻繁に参照するアプリケーションでは、通常の with() によるEagerロードと組み合わせて活用すると効果的です。

次のステップ

リレーションシップ

belongsToManyを含む基本的なリレーションの定義方法に戻って復習します。

Eloquent Observers とモデルイベント

モデルイベントを使ってピボットモデルの保存・更新をフックする方法を学びます。
最終更新日 2026年9月8日