1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravelでの多対多リレーションの設定方法

Last updated at Posted at 2024-09-25

はじめに

この記事は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モデルでリレーションを設定します。

Order.php
<?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');
    }
}
Product.php
<?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 メソッドの補足

Product.php
public function products()
{
    return $this->belongsToMany(Order::class, 'orders_products', 'product_id', 'order_id');
}
  1. 関連するモデルクラス(ここでは Order::class)
  2. 中間テーブル名(ここでは 'orders_products')
  3. 現在のモデルの外部キー(中間テーブルの 'product_id')
  4. 関連するモデルの外部キー(中間テーブルの '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メソッドを使ってリレーションを設定する
  • リレーションを設定することで、関連するデータを簡単に取得できる
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?