BLOG

ブログ

2024/01/16 技術系

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

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

前回のブログ で『1対1のリレーション(hasOne)』について掘り下げてみました!
今回は、Eloquentのリレーションのうち、1対多のリレーションについてまとめていきます💪

1対多のリレーション(hasMany

まずは、1対多のリレーションの定義をおさらいしておきます👀

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

前回1対1のリレーションの場合の親モデル側の定義が『hasOne』であったのに対し、1対多では『hasMany』と複数の子モデルを持っているということがわかりやすく定義されています。

hasManyのリレーション定義方法について例を用いて整理していきます🖋️

前提

今回はブログ記事📝とコメント💬を例にします。
1件のブログには1件以上コメントができるものとします。(コメントがないブログも存在する前提)

DB定義

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

ブログ記事テーブル📝

カラム名コメント
idブログ記事ID
blog_codeブログコード
titleタイトル
contentブログ内容
ブログテーブル(blogs)

コメントテーブル💬

カラム名コメント
idコメントID
blog_idブログID
comment_codeコメントコード
commentコメント
コメントテーブル(comments)

モデル定義

ブログ記事モデル📝(親)

この『1件のブログには1種類以上コメントができる』という関係をBlogモデル内にcommentsメソッドで定義するため、hasManyメソッドを使用します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    /**
     * ブログへのコメントを取得
     */
    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}

ここでhasManyメソッドを使用することで、引数で渡したクラスのモデルを複数返してくれます。

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

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

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    /**
     * ブログへのコメントを取得
     */
    public function comments()
    {
        // blog_id 以外の外部キーに(comment_code を外部キーに指定)したい時
        return $this->hasMany(Comment::class, 'comment_code');
    }
}
  • 第3引数
    • 親モデルのキーを指定することができます。 例えば、blogs.id ではなく、blogs.blog_code をキーにして紐づけたいときは、以下のように指定します。
ER図
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    /**
     * ブログへのコメントを取得
     */
    public function comments()
    {
        // blog_id 以外の外部キーにし、さらに親モデル側のキーを blogs. blog_code に設定したいとき
        return $this->hasMany(Comment::class, 'comment_code', 'blog_code');
    }
}

コメントモデル💬(子)

今度は『複数のコメントができる一件のブログ』という逆の関係の定義も必要なので、Commentモデル側にも定義をしていきます。コメントされるブログへアクセスできるCommentモデルのリレーションを定義するには、belongsToメソッドを使用します。

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
     * コメントしているブログを取得
     */
    public function blog()
    {
        return $this->belongsTo(Blog::class);
    }
}

blogメソッドを呼び出す時の挙動は、
Commentモデルが持っているblog_idカラムと同じidを持つBlogモデルを取得する
となります。

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

  • 第2引数
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
     * コメントしているブログを取得
     */
    public function blog()
    {
        // blog_id 以外の外部キーに(comment_code を外部キーに指定)したい時
        return $this->belongsTo(Blog::class, 'comment_code');
    }
}
  • 第3引数
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
     * コメントしているブログを取得
     */
    public function blog()
    {
        // blog_id 以外の外部キーにし、さらに親モデル側のキーを blog.blog_code に設定したいとき
        return $this->belongsTo(Blog::class, 'comment_code', 'blog_code');
    }
}

まとめ

今回は、使用頻度も高い1対多のリレーションの定義方法をまとめてみました。
Eloquentの機能をしっかり使えるようにすることで得られるメリットは以前のブログでも書かせていただいていますが、Eloquentモデルオブジェクトで返してくれてデータ型も担保されている上に、その後のデータの取り扱いを便利にしてくれるクエリビルダも使うことができます👍
自由自在に使いこなせるととっても重宝すること間違いなしです🙌

次回はいよいよ三部作最終章『多対多』について書きたいと思います!



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

アーカイブ