Laravel リレーションのまとめ（一対多 多対多 ）

リレーションについて毎回調べてしまっていることが多いので、内容整理として。
（随時更新）

#前提
バージョン：Laravel6

#一対多

##①一対多とは
一対多のリレーションとは、あるmodelインスタンス一つ(ModelA)に対して複数のmodelインスタンス(ModelB)が紐づく関係のこと。その「紐づき」にあたるものが外部キー。あるModelAインスタンスには複数のModelBインスタンスが紐づくが、あるModelBインスタンスは特定のModelAインスタンスにだけ紐づく。

##②migration
```php:create_model_a_table.php
//ModelAマイグレーション
public function up()
{
    Schema::create('model_a', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->timestamps();
    });
}
```

```php:create_model_b_table.php
//ModelBマイグレーション
public function up()
{
    Schema::create('model_b', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->unsignedBigInteger('model_a_id'); // 外部キー
        $table->string('name');
        $table->timestamps();
        
        // 外部キー制約
        $table->foreign('model_a_id')->references('id')->on('model_a')->onDelete('cascade');
    });
}
```

外部キー制約は`foreign('外部キー')->references('参照先のカラム')->on('参照テーブル')`と記述する。
`onDelete('**')`はデータ削除時の振舞いを指定するもの。

* `cascade`：参照先が削除されると、共に削除される。
* `set null`：参照先が削除されると、外部キーがnullになる。
* `restrict`：参照先が削除されると、エラーを返す。

##③model
```php:ModelA.php
// このインスタンスに紐づくModelBインスタンス
public function modelBs() {
    return $this->hasMany(ModelB::class);
}

// このインスタンスに紐づくインスタンスの数を取得する。
public function loadRelationshipCounts() {
    $this->loadCount('modelBs');
}
```

```php:ModelB.php
// このインスタンスに紐づくModelAインスタンス
public function modelA() {
    return $this->belongsTo(ModelA::class);
}
```

#多対多

##①多対多とは
多対多のリレーションとは、あるmodelインスタンス群(ModelC)に対して複数のmodelインスタンス群(ModelD)が紐づく関係のこと。一対多とは異なり、あるModelCインスタンスが複数のModelDインスタンスと紐づくだけでなく、あるModelDインスタンスが複数のModelCインスタンスと紐づくことができる。
多対多を実現するには中間テーブルを用いる。

##②migration
```php:create_model_c_table.php
//ModelCマイグレーション
public function up()
{
    Schema::create('model_c', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->timestamps();
    });
}
```

```php:create_model_d_table.php
//ModelDマイグレーション
public function up()
{
    Schema::create('model_d', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->timestamps();
    });
}
```

```php:create_relay_c_d_table.php
//中間テーブルマイグレーション
public function up()
{
    Schema::create('relay_c_d', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->unsignedBigInteger('model_c_id'); // 外部キー
        $table->unsignedBigInteger('model_d_id'); // 外部キー
        $table->string('name');
        $table->timestamps();
        
        // 外部キー制約
        $table->foreign('model_a_id')->references('id')->on('model_c')->onDelete('cascade');
        $table->foreign('model_a_id')->references('id')->on('model_d')->onDelete('cascade');
    });
}
```
外部キー制約は`foreign('外部キー')->references('参照先のカラム')->on('参照テーブル')`と記述する。
`onDelete('**')`はデータ削除時の振舞いを指定するもの。

* `cascade`：参照先が削除されると、共に削除される。
* `set null`：参照先が削除されると、外部キーがnullになる。
* `restrict`：参照先が削除されると、エラーを返す。

##③model
```php:ModelC.php
// このインスタンスに紐づくModelDインスタンス
public function modelDs() {
    return $this->belongsToMany(ModelB::class, 'relay_c_d', 'model_c_id', 'model_d_id')->withTimestamps();
}

// このインスタンスに紐づくインスタンスの数を取得する。
public function loadRelationshipCounts() {
    $this->loadCount('modelDs');
}
```

```php:ModelD.php
// このインスタンスに紐づくModelCインスタンス
public function modelCs() {
    return $this->belongsToMany(ModelC::class, 'relay_c_d', 'model_d_id', 'model_c_id')->withTimestamps();
}

// このインスタンスに紐づくインスタンスの数を取得する。
public function loadRelationshipCounts() {
    $this->loadCount('modelCs');
}
```