BLOG

ブログ

2023/05/23 技術系

Laravelのリレーション整理:1対1のリレーション【hasOneとbelongsTo】

この記事を書いた人 M.Y
画像1

前回のブログでLaravelにはとても便利な ORM(Eloquent)があらかじめ用意されています!と紹介しましたが、このEloquentのリレーションについて掘り下げてみたいと思います🖋️

Laravelのリレーションの定義方法

リレーション定義はModel内で設定します。リレーションは以下に分類されます。

  • 1対1
  • 1対多
  • 多対多

それぞれのリレーション定義について整理してみます。

1対1、1対多

となる側にhasOne(1対1), hasMany(1対多)を、となる側にbelongsTo(1対1, 1対多)を定義することで、どちらが親子関係にあるのかを定義することができます。

親モデル側の定義モデル側の定義
1対1hasOnebelongsTo
1対多hasManybelongsTo

親モデルが子モデルを何個持っているか、という感じになるのでhasOneが主(親)であることがわかりやすいですね!
一方、子モデルには従属という意味のbelongsToを定義します。

多対多

多対多の場合は中間テーブルを設ける必要があります。
その中間テーブルに紐づけるモデルそれぞれにbelongsToManyを定義します。

モデル1モデル2
多対多belongsToManybelongsToMany

複数ひもづくので複数に従属するbelongsToManyとなります。

定義方法について、まず今回は、hasOneのリレーションについて整理してみたいと思います🖋️

1対1のリレーション(hasOne

前提

今回は従業員🙎と、会社で貸与しているPC💻を例にします。
会社が貸与するPCは一人につき1台🧑‍💻とします。

DB定義

DB構造は以下のようになります。

従業員テーブル🙎

カラム名コメント
id従業員ID
staff_code従業員コード
name従業員名
従業員テーブル(employees)

PCテーブル💻

カラム名コメント
idPCID
employee_id従業員ID
owner_code所有者コード
PCテーブル(pcs)

モデル定義

従業員モデル🙎(親)

この『一従業員に対しPCは一台しか貸与しない』という関係をEmployeeモデル内にpcメソッドで定義するため、hasOneメソッドを使用します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{
    /**
     * 従業員に貸与しているPCの取得
     */
    public function pc()
    {
        return $this->hasOne(Pc::class);
    }
}

ここでhasOneメソッドを使用することで、引数で渡したクラスのモデルを1つだけ返してくれるようになります。

hasOneメソッドに渡す最初の引数は、関連するモデルクラスの名前です。
hasOneメソッドはオプションで第3引数まで設定できます。
上記は、第2引数や第3引数を省略することで、pcテーブルのemployee_idが紐づくよう規約で自動的にリレーションしてくれます。
第2引数や第3引数を設定することで、リレーションするカラムの紐付けを指定するよう設定が可能です。

  • 第1引数
    • 関連するモデルクラスの名前を設定します。
      第1引数のみを指定している場合は、子モデルに設定されている親モデル名_idのカラムと紐付けします。
ER図
  • 第2引数
    • 子モデルの外部キーを指定することができます。例えば、pcs.owner_code を紐づけたいときは、以下のように指定します。
ER図
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{
    /**
     * 従業員に貸与しているPCの取得
     */
    public function pc()
    {
        // employee_id 以外の外部キーに(owner_code を外部キーに指定)したい時
        return $this->hasOne(Pc::class, 'owner_code');
    }
}
  • 第3引数
    • 親モデルのキーを指定することができます。 例えば、employees.id ではなく、employees.staff_code をキーにして紐づけたいときは、以下のように指定します。
ER図
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{
    /**
     * 従業員に貸与しているPCの取得
     */
    public function pc()
    {
        // employee_id 以外の外部キーにし、さらに親モデル側のキーを employees.staff_code に設定したいとき
        return $this->hasOne(Pc::class, 'owner_code', 'staff_code');
    }
}

PCモデル💻(子)

今度は『会社が貸与するPCは一人につき1台』という逆の関係の定義も必要なので、PCモデル側にも同様の定義をしていきます。 PCを貸与されている従業員へアクセスできるPCモデルのリレーションを定義するには、belongsToメソッドを使用します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Pc extends Model
{
    /**
     * このPCを貸与している従業員の取得
     */
    public function employee()
    {
        return $this->belongsTo(Employee::class);
    }
}

employeeメソッドを呼び出す時の挙動は、
Pcモデルが持っているemployee_idカラムと同じidを持つEmployeeモデルを取得する
となります🧑‍💻

こちらも、前述のhasOneメソッド同様に第3引数まで指定することが可能で、同じく引数を指定することで外部キーのオーバーライドを設定することができます💡

  • 第2引数
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Pc extends Model
{
    /**
     * このPCを貸与している従業員の取得
     */
    public function employee()
    {
        // employee_id 以外の外部キーに(owner_code を外部キーに指定)したい時
        return $this->belongsTo(Employee::class, 'owner_code');
    }
}
  • 第3引数
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Pc extends Model
{
    /**
     * このPCを貸与している従業員の取得
     */
    public function employee()
    {
        // employee_id 以外の外部キーにし、さらに親モデル側のキーを employees.staff_code に設定したいとき
        return $this->belongsTo(Employee::class, 'owner_code', 'staff_code');
    }
}

まとめ

今回は、一番シンプルでとてもよく使う1対1のリレーションの定義方法をまとめてみました。
Eloquentの機能は便利なので、しっかり身につけてより活用していきたいと思っています。
次回は1対多について、書きたいなと思っています!



株式会社ウイングドアは福岡のシステム開発会社です。
現在、私達と一緒に"楽しく仕事が出来る仲間"として、新卒・中途採用を絶賛募集しています!
ウイングドアの仲間達となら楽しく仕事できるかも?と興味をもった方、
お気軽にお問い合わせ下さい!

アーカイブ