役立つ情報
登録日: 2025-03-21   最終更新日: 2025-03-21
  • Laravel
  • PHP

Laravel リレーション(1対1(hasOne)、1対多(hasMany)、多対多(belongsTo))について

Laravel でテーブル間のリレーションを設定することにより一定のルールに基づいてデータベースに登録されたデータを参照すくことができます。

リレーションの種類

Laravel リレーションは、以下の3種類あります。

  • hasOne(1対1)
  • hasMany(1対多)
  • belongsTo(多対多)

hasOne(1対1)について

hasOne(1対1)は、2つのテーブル間でデータが1対1の関係になるデータを取得する際に利用します。

 ログイン管理テーブル(logins)       ユーザ管理テーブル(users)
┌------------------------┐         ┌------------------------------┐
|id  | mailAddress       |         |id   | userName      | status |
├------------------------┤   -->   ├------------------------------┤
|1   | admin@example.com |+-------+|1    | Admin User    | true   |
├------------------------┤         ├------------------------------┤
|2   | user@example.com  |         |2    | Dev User      | false  |
└------------------------┘         └------------------------------┘

SQLで表現すると以下のようになります。


SELECT
    login.*
FROM
    login
    INNER JOIN user ON (login.id = user.id)

app\Models\Login.php


<?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\hasOne;

class Login extends Model
{
    use HasFactory;
    protected $table = 'logins';

    // リレーション設定
    public function userHasOne()
    {
        return $this->hasOne(User::class);
    }
}

app\Models\User.php


<?php

namespace App\Models;

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

class User extends Model
{
    use HasFactory;
    protected $table = 'users';
}

呼び出す方法


var_dump(Login::userHasOne());

hasMany(1対多)について

hasMany(1対多)は、2つのテーブル間でデータが1対多の関係になるデータを取得する際に利用します。

 都道府県テーブル(prefs)            市区町村テーブル(citys)
┌------------------------┐         ┌-----------------------------┐
|id  | prefName          |         |id   | prefId | cityName     |
├------------------------┤   -->   ├-----------------------------┤
|1   | tokyo             |+-------+|1    | 1      | Chiyoda      |
├------------------------┤   |    ├-----------------------------┤
|2   | osaka             |   ├---+|2    | 1      | Chuo         |
└------------------------┘   |    ├-----------------------------┤
                               └---+|3    | 1      | Minato       |
                                     ├-----------------------------┤
                                     |4    | 2      | Osaka        |
                                     └-----------------------------┘

SQLで表現すると以下のようになります。


SELECT
    prefs.prefName,
    citys.cityName
FROM
    prefs
    INNER JOIN citys ON (prefs.id = citys.prefId)

app\Models\Pref.php


<?php

namespace App\Models;

use App\Models\City;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\hasMany;

class Pref extends Model
{
    use HasFactory;
    protected $table = 'prefs';

    // リレーション設定
    public function cityHasMany()
    {
        return $this->hasMany(City::class);
    }
}

app\Models\City.php


<?php

namespace App\Models;

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

class City extends Model
{
    use HasFactory;
    protected $table = 'citys';
}

呼び出す方法


var_dump(Pref::cityHasMany());

belongsTo(多対多)について

belongsTo(多対多)は、2つのテーブル間に中間テーブルがある場合でデータを取得する際に利用します。
※ 記事テーブル -> タグテーブルを参照する場合。
※ タグテーブル -> 記事テーブルを参照する場合。

 記事テーブル(contents)   中間テーブル(c_t_relation)  タグテーブル(tags)                
┌---------------┐         ┌-----------------┐         ┌------------------┐
|id  | title    |         |contentId | tagId|         |id | tagName      |
├---------------┤   -->   ├-----------------┤   <--   ├------------------┤
|1   | contentA |+-------+|1         | 1    |+-------+|1  | php          |
├---------------┤   |    ├-----------------┤    |   ├------------------┤
|2   | contentB |   ├---+|1         | 2    |    |   |2  | Laravel      |
├---------------┤   |    ├-----------------┤    |   ├------------------┤
|3   | contentC |   └---+|1         | 3    |    |   |3  | MySQL        |
├---------------┤         ├-----------------┤    |   ├------------------┤
|4   | contentD |         |2         | 1    |+---┤   |4  | Apache       |
└---------------┘         ├-----------------┤    |   └------------------┘
                            |2         | 2    |    |
                            ├-----------------┤    |
                            |3         | 1    |+---┘
                            └-----------------┘

app\Models\Content.php


<?php

namespace App\Models;

use App\Models\Tag;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\belongsTo;

class Content extends Model
{
    use HasFactory;
    protected $table = 'contents';

    // リレーション設定
    public function tagBelongsTo()
    {
        return $this->belongsTo(Tag::class);
    }
}

app\Models\Tag.php


<?php

namespace App\Models;

use App\Models\Content;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\belongsTo;

class Tag extends Model
{
    use HasFactory;
    protected $table = 'tags';

    // リレーション設定
    public function contentBelongsTo()
    {
        return $this->belongsTo(Content::class);
    }
}

呼び出す方法


var_dump(Content::tagBelongsTo());
var_dump(Tag::contentBelongsTo());

belongsTo(多対多)応用編

多対多で中間テーブルのデータを参照したい場合。

app\Models\Content.php


<?php

namespace App\Models;

use App\Models\Tag;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\belongsTo;

class Content extends Model
{
    use HasFactory;
    protected $table = 'contents';

    // リレーション設定
    public function tagBelongsTo()
    {
        return $this->belongsTo(
                   Tag::class, 'c_t_relation', 'contentId', 'tagId'
               );
    }
}

Copyright 役立つ情報.net