はじめに
この記事はLaravelで多対多リレーションを構築したい場合の設定方法に関する手順をまとめたメモになります
多対多リレーションについての具体例
Laravelを使っていると、モデル同士が多対多(Many-to-Many)の関係になることがあります。例えば、注文(Order)と商品(Product)の関係が該当します。
モデルを作成するコマンド
php artisan make:model Order
php artisan make:model Product
中間テーブルの作成
多対多のリレーションでは、中間テーブルを使って2つのテーブル間の関係を管理します。
例えば、ordersテーブル
とproductsテーブル
の間にorders_products
という中間テーブルを作成します。
php artisan make:migration create_orders_products_table --create=orders_products
注意点
中間テーブル(orders_products)にはモデルやリレーションの設定は不要です。中間テーブルは、あくまで2つのモデル間のリレーションを管理するためのもので、直接データを操作することは通常ありません。そのため、リレーションの設定はOrderモデルとProductモデルで行います。
中間テーブルのマイグレーションについて
このマイグレーションは、orders テーブルと products テーブルの間に多対多の関係を持たせるための 中間テーブル orders_products を作成します。
public function up(): void
{
Schema::create('orders_products', function (Blueprint $table) {
$table->id();
$table->foreignId('order_id')->constrained()->onDelete('cascade');
$table->foreignId('product_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
この中間テーブルには、order_id と product_id という外部キーが含まれており、これによってそれぞれのテーブルとのリレーションが形成されます。
コードの補足
中間テーブルを作成するにあたって使用されるメソッドについて、以下の通り補足説明を記載します
$table->id();
この行は、主キー
を生成するためのコードです。自動増分の id 列
を作成し、このテーブルの主キー
として機能します
$table->foreignId('order_id')
order_id 列
を作成し、これは orders テーブル
の id
を参照する外部キーとなります
->constrained()
orders テーブル
に対して外部キー制約を設定します。デフォルトでは、order_id 列は orders.id
を参照することになります。
->onDelete('cascade');
products テーブル
のレコードが削除された場合、関連する orders_products テーブルのレコードも削除されます
(cascadeは固定のキーワードです)
モデルでのリレーション設定
中間テーブルの準備ができたので、次にOrderモデルとProductモデルでリレーションを設定します。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Product; // Productクラスのインポート
class Order extends Model
{
public function products()
{
return $this->belongsToMany(Product::class, 'orders_products', 'order_id', 'product_id');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Order; // Orderクラスのインポート
class Product extends Model
{
public function orders()
{
return $this->belongsToMany(Order::class, 'orders_products', 'product_id', 'order_id');
}
}
belongsToManyメソッド
を使用して、多対多のリレーションを定義します。ここでは、orders_products
という中間テーブルを指定し、それぞれの外部キーを指定しています。
中間テーブルにモデルは不要
中間テーブルを使った多対多のリレーション
は、belongsToManyメソッドを使用するだけで中間テーブルを操作できます。中間テーブルに追加のフィールドがある場合もしくは、特別なロジックを記述したい場合以外は、中間テーブル用のモデルを作成する必要がありません
belongsToMany メソッドの補足
public function products()
{
return $this->belongsToMany(Order::class, 'orders_products', 'product_id', 'order_id');
}
- 関連するモデルクラス(ここでは Order::class)
- 中間テーブル名(ここでは 'orders_products')
- 現在のモデルの外部キー(中間テーブルの 'product_id')
- 関連するモデルの外部キー(中間テーブルの 'order_id')
順番の重要性
- 現在のモデルの外部キー(product_id)と関連するモデルの外部キー(order_id)の順番は重要です
- 最初の外部キー(この場合は product_id)は、現在のモデル(Product)のテーブルに存在する外部キーを指定します
- 2番目の外部キー(この場合は order_id)は、関連するモデル(Order)のテーブルに存在する外部キーを指定します
順番を入れ替えた場合
もし引数の順番を逆にすると、意図したリレーションが構築されなくなります。つまり、belongsToMany(Order::class, 'orders_products', 'order_id', 'product_id') とした場合、order_id が Product テーブルに関連する外部キーとして扱われてしまうため、正しい動作をしなくなります。
リレーションの使用例
1つの注文に関連する商品を取得する場合
$order = Order::find(1);
$products = $order->products;
foreach ($products as $product) {
echo $product->name;
}
1つの商品に関連する注文を取得する場合
$product = Product::find(1);
$orders = $product->orders;
foreach ($orders as $order) {
echo $order->id;
}
このように、Orderモデルから関連するProductを取得したり、Productモデルから関連するOrderを取得することができます。
まとめ
Laravelでの多対多リレーションの設定方法について重要なポイントは以下の通りです
- 多対多リレーションでは、中間テーブルを作成する
- 中間テーブルにはモデルやリレーションの設定は不要
- モデルでbelongsToManyメソッドを使ってリレーションを設定する
- リレーションを設定することで、関連するデータを簡単に取得できる