リレーション

記事の内容

概要

リレーションは、複数のテーブル間の関係性を簡単に定義し、データを効率的に取得するための機能です。

メソッド名説明
hasOne1対1リレーションを定義
hasMany1対多リレーションを定義
belongsTo親モデルへのリレーションを定義
belongsToMany多対多リレーションを定義

1対1

関係性

Customer ─ Membership
├─Rental ─ Item
│  └─── Item
│  ┌────┘
└─Rental ─ Item
   └─── Item

・1人のCustomer(顧客)が1つのMembership(会員証)を持つ
・Membershipは1人のCustomerに属する

【ファイル先】app/Models/Customer.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    use HasFactory;

    public function membership()
    {
        return $this->hasOne(Membership::class);
    }
}

【ファイル先】app/Models/Membership.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Membership extends Model
{
    use HasFactory;

    public function customer()
    {
        return $this->belongsTo(Customer::class);
    }
}

1対多

関係性

Customer ─ Membership
├─Rental ─ Item
  └─── Item
  ┌────┘
└─Rental ─ Item
   └─── Item

・1人のCustomer(顧客)は複数のRental(レンタル履歴)を持つ
・Rentalは1人のCustomerに属する

【ファイル先】app/Models/Customer.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    use HasFactory;

    public function rentals()
    {
        return $this->hasMany(Rental::class);
    }
}

【ファイル先】app/Models/Rental.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Rental extends Model
{
    use HasFactory;

    public function customer()
    {
        return $this->belongsTo(Customer::class);
    }
}

多対多

関係性

Customer ─ Membership
├─Rental ─ Item
│  └─── Item
│  ┌────┘
└─Rental ─ Item
   └─── Item

・1つのRental(レンタル履歴)は複数のItem(商品)を含む
・1つのItemも複数のRentalに属する

【ファイル先】app/Models/Rental.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Rental extends Model
{
    use HasFactory;

    public function items()
    {
        return $this->belongsToMany(Item::class);
    }
}

【ファイル先】app/Models/Item.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    use HasFactory;

    public function rentals()
    {
        return $this->belongsToMany(Rental::class);
    }
}

その他

条件付きリレーション

リレーションに対して条件を追加することで、特定のデータだけを取得することができます。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    use HasFactory;

    // 通常のリレーション
    public function rentals()
    {
        return $this->hasMany(Rental::class);
    }

    // 条件付きリレーション
    public function activeRentals()
    {
        return $this->hasMany(Rental::class)->where('status', 'active');
    }
}

リレーションのデフォルトモデル

リレーションが存在しない場合に、デフォルトのモデルを返す方法があります。
withDefaultメソッドを使うことで実現可能

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    use HasFactory;

    /**
     * Customerは1つのMembershipを持つ(1対1のリレーション)
     * リレーションが存在しない場合、デフォルトの値を返す
     */
    public function membership()
    {
        // hasOneリレーションを定義し、デフォルトで 'type' => 'standard' を設定
        return $this->hasOne(Membership::class)->withDefault([
            'type' => 'standard',
        ]);
    }
}

カスタム中間テーブルのデータ

多対多のリレーションでは、中間テーブルに追加のフィールドがある場合、
そのフィールドを取得・操作することができます。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Rental extends Model
{
    use HasFactory;

    /**
     * Rentalは多くのItemと多対多のリレーションを持つ
     * 中間テーブルには 'rental_date' フィールドも含まれる
     */
    public function items()
    {
        // belongsToManyリレーションを定義し、中間テーブルの 'rental_date' を使用可能にする
        return $this->belongsToMany(Item::class)->withPivot('rental_date');
    }
}

リレーションのサブクエリ

リレーション内でサブクエリを使って、集計や特定の条件に合致するデータを効率的に取得できます。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    use HasFactory;

    /**
     * Customerの最新のRentalを取得
     * latest()を使って、最も新しいRentalを1つ取得する
     */
    public function latestRental()
    {
        // hasOneリレーションを定義し、最新のRentalを取得
        return $this->hasOne(Rental::class)->latest();
    }
}
記事の内容
閉じる