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

## はじめに
この記事はLaravelで多対多リレーションを構築したい場合の設定方法に関する手順をまとめたメモになります

## 多対多リレーションについての具体例
Laravelを使っていると、モデル同士が多対多（Many-to-Many）の関係になることがあります。例えば、注文（Order）と商品（Product）の関係が該当します。

### モデルを作成するコマンド

```bash
php artisan make:model Order
php artisan make:model Product
```

## 中間テーブルの作成

多対多のリレーションでは、中間テーブルを使って2つのテーブル間の関係を管理します。

例えば、`ordersテーブル`と`productsテーブル`の間に`orders_products`という中間テーブルを作成します。

```bash
php artisan make:migration create_orders_products_table --create=orders_products
```

### 注意点
中間テーブル（orders_products）にはモデルやリレーションの設定は不要です。中間テーブルは、あくまで2つのモデル間のリレーションを管理するためのもので、直接データを操作することは通常ありません。そのため、リレーションの設定は**Orderモデル**と**Productモデル**で行います。

## 中間テーブルのマイグレーションについて
このマイグレーションは、orders テーブルと products テーブルの間に多対多の関係を持たせるための 中間テーブル orders_products を作成します。
```php
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）
1. 中間テーブル名（ここでは 'orders_products'）
1. 現在のモデルの外部キー（中間テーブルの 'product_id'）
1. 関連するモデルの外部キー（中間テーブルの '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つの注文に関連する商品を取得する場合
```php
$order = Order::find(1);
$products = $order->products;

foreach ($products as $product) {
    echo $product->name;
}
```
1つの商品に関連する注文を取得する場合
```php
$product = Product::find(1);
$orders = $product->orders;

foreach ($orders as $order) {
    echo $order->id;
}
```

このように、Orderモデルから関連するProductを取得したり、Productモデルから関連するOrderを取得することができます。

## まとめ

Laravelでの多対多リレーションの設定方法について重要なポイントは以下の通りです

- 多対多リレーションでは、中間テーブルを作成する
- 中間テーブルにはモデルやリレーションの設定は不要
- モデルでbelongsToManyメソッドを使ってリレーションを設定する
- リレーションを設定することで、関連するデータを簡単に取得できる