[Laravel] 1対1・1対多リレーションの定義とデータの取得方法

ER図の画像 Laravel

Laravelにおいて1対1・1対多リレーションを定義する方法と、定義したリレーションを用いてデータを取り出す方法を解説します。

筆者自身かなり躓いたので、自身の復習も兼ねて筆者が理解した範囲でまとめています。

なお1対1と1対多は扱いがかなり似ているので、1対多メインで解説しながら異なる箇所のみ「1対1」の説明を入れていきます。

1対1についてはこのメモマークで補足説明します。

1対多のイメージ・ER図

説明していくにあたって、とあるフリマサイトを想定します。

商品の情報(名前など)がItemsテーブルに入っており、商品の状態(とても良い・良い・悪い・とても悪い)を表すデータがConditionsテーブルに入っています。

Itemsテーブルに外部キーとしてCondition_idが存在し、ItemsテーブルとConditionsテーブルをつないでいます。

idname(状態)
1とても良い(傷なし・美品)
2良い(傷なし)
3悪い(傷あり)
4とても悪い(大きな傷あり)
Conditionsテーブルのイメージ
idcondition_idname(商品名)
12(良い)
21(とても良い)シャツ
31(とても良い)スーツ
44(とても悪い)ハンカチ
Itemsテーブルのイメージ

ここで、2番目の表「Itemsテーブルのイメージ」を見ると、Condition_idに同じ数字(シャツとスーツがともに1:とても良いになっている)が入っています。このように、Condition1つに対して複数のItemが結びつくことができるので、ConditionとItemは1対多の関係になります。

ここでCondition_idに同じ数字が入らないような場合、Conditionとitemは1対1の関係になるイメージです。

ER図にするとこんな感じ。PKは主キー、FKは外部キーです。

1対1の場合、両テーブルともConditionsテーブルについているような縦線2本になります。

主と従(親と子)

リレーションには主従(親子)関係があります。

  • 主(親):外部キーがない側(Conditionsテーブル)
  • 従(子):外部キーがある側(Itemsテーブル)

余談ですが筆者はここで混乱しました。というのも、Itemsテーブルのほうが様々な情報が入っており、「こちらが主じゃないの?」と思ってしまったからです。

分からなくなってしまう場合は単純に外部キーの有無で覚えるのがいいと思います。

コードの記述

ここからは実際にコードを書いていきます。

モデルへの記述

主テーブルのモデル(Condition.php)

まずは主テーブルのモデル(Condition.php)への記述。

<?php

namespace App\Models;

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

class Condition extends Model
{
    use HasFactory;
    protected $fillable = [
        'name'
    ];

    public function item()
    {
        return $this->hasMany(Item::class);
    }
}

この部分がリレーションに必要な記述です。

public function item()
    {
        return $this->hasMany(Item::class);
    }

1対多の場合は「hasMany」を用います。hasMany(Item::class)の「Item」は従テーブルのモデル名です。

public function item() の「item」は何でも良いですが、従テーブルのモデル名と同じにしておくのが無難そうです(データを取り出すときにこれを使います)。

1対1の場合は「hasMany」の代わりに「hasOne」を使います。あとは同じです。

従テーブルのモデル(Item.php)

続いて従テーブルのモデル(Item.php)への記述。

<?php

namespace App\Models;

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

class Item extends Model
{
    use HasFactory;
    protected $fillable = [
        'name',
    ];

    public function condition()
    {
        return $this->belongsTo(Condition::class);
    }
}

この部分がリレーションに必要な記述です。

public function condition()
    {
        return $this->belongsTo(Condition::class);
    }

こちらは「belongsTo」を用います。belongsTo(Condition::class)の「Condition」部分は主テーブルのモデル名を記述します。

こちらは1対1の場合も同じく「belongsTo」です。

リレーションに必要な記述はたったこれだけ。これで2つのテーブルが結びつきました。

データの取り出し

続いてデータの取り出しに移ります。

今回は、下の表でid=1の靴の状態、すなわち「良い」という言葉を取り出していきたいと思います。

idcondition_idname(商品名)
12(良い)
21(とても良い)シャツ
31(とても良い)スーツ
44(とても悪い)ハンカチ
Itemsテーブルのイメージ

コントローラへの記述

public function view()
    {
        $condition = Item::find(1)->condition->name;
        return view('/', compact('condition'));
    }

「Item::find(1)」でItemテーブルからid=1(靴)のデータすべてを取り出し、続いて「->condition」(モデルに記述したメソッド名、public function condition() の「condition」部分)で靴のConditionデータ(id=2, name=良い)を取り出し、さらにそこから「->name」で必要なデータ(name=良い)のみを取り出しています。

ビューファイルへの記述

あとはビューファイルの「良い」という文字を表示させたい箇所で以下の記述をすればOKです。

{{ $condition }}

まとめ

以上、1対1・1対多リレーションの記述方法でした。概要をまとめます。

  • 主と従:外部キーがない=主、外部キーがある=従
  • 主テーブルのモデル:1対1ならhasOne、1対多ならhasMany
  • 従テーブルのモデル:belongsTo

以外に単純だと感じた方も多いのではないかと思います。参考にしていただければ幸いです。

読んでくださってありがとうございました。

コメント

タイトルとURLをコピーしました