5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravelでリレーション先のリレーションのデータを取得する時にHas Many Throughが便利っていう話

Posted at

前書き

タイトルまんまですが、Laravelでリレーション先のリレーションのデータを取得する時にHas Many Throughが便利っていう話になります。
書き方とHas Many Throughを使わない場合との書き方の違い、簡単な活用方法等を書いていきます。

サービス概要

今回はユーザーが記事などを投稿して記事にコメントをできるようなサービスを考えてみます。

環境

Laravel 10系

テーブル設計

users(ユーザー)テーブル

論理名 物理名 データ型 制約
ユーザーID id UNSIGNED BIGINT PRIMARY KEY,
AUTOINCREMENT
ユーザー名 name VARCHAR(255) NOT NULL
作成日時 created_at TIMESTAMP NOT NULL
更新日時 updated_at TIMESTAMP

posts(投稿)テーブル

論理名 物理名 データ型 制約
投稿ID id UNSIGNED BIGINT PRIMARY KEY,
AUTOINCREMENT
ユーザーID user_id UNSIGNED INTEGER NOT NULL
タイトル title VARCHAR(255) NOT NULL
本文 content TEXT NOT NULL
作成日時 created_at TIMESTAMP NOT NULL
更新日時 updated_at TIMESTAMP

comments(コメント) テーブル

論理名 物理名 データ型 制約
コメントID id UNSIGNED BIGINT PRIMARY KEY,
AUTOINCREMENT
ユーザーID user_id UNSIGNED INTEGER NOT NULL
投稿ID post_id UNSIGNED INTEGER NOT NULL
コメント内容 content TEXT NOT NULL
作成日時 created_at TIMESTAMP NOT NULL
更新日時 updated_at TIMESTAMP

リレーションの実装

Has Many Throughの使い方

User.phpにリレーションを設定していきます。

User.php
public function post_comments()
{
    return $this->hasManyThrough(Comment::class, Post::class);
}

今回はローカルキーや外部キーは特殊なパターンではないので第三引数以降を設定する必要がありません。

User.php
public function post_comments()
{
    return $this->hasManyThrough(
        Comment::class,
        Post::class,
        'user_id', // postsテーブル(中間)の外部キー
        'post_id', // commentsテーブルの外部キー
        'id', // usersテーブルのローカルキー
        'id' // テーブルのローカルキー
    );
}

ローカルキーや外部キーをカスタムしている場合は第三引数以降を設定することを忘れないようにしてください。

詳しい設定は公式ドキュメントを見ていただければと思います。

使ってみる

書き方はシンプルです。

$users = User::with('post_comments')->get();

これでユーザーの投稿に紐つくコメントが取得できます。

$users = User::withCount('post_comments')->get();

こうすることでユーザーごとに投稿に紐つくコメントの総数が取得できます。

もちろん条件で絞り込みすることもできます。
以下では昨日から今日にかけて作られたユーザーごとに投稿に紐つくコメントの総数が取得できます。

$today = Carbon::now();
$yesterday = Carbon::yesterday();
$users = User::withCount([
    'post_comments' => function ($q) use ($today, $yesterday) {
        $q->whereBetween('created_at', [$yesterday, $today]);
    }
]);

Has Many Throughを使わない場合

リレーションの設定

User.phpとPost.phpにリレーションを設定していきます。

User.php
public function posts()
{
    return $this->hasMany(Post::class);
}
Post.php
public function comments()
{
    return $this->hasMany(Comment::class);
}

使ってみる

$users = User::with('posts.comments')->get();

これでユーザーの投稿とそれに紐つくコメントが取得できます。

投稿とコメント両方必要なパターンはこれで良いと思います。

Has Many Throughはどういう時に使うのが良いか

私は中間のデータが必要ない時などに使用しております。
Has Many Throughを使うことで取得するデータの量も減りますし階層が浅くなるので取り扱いがしやすくなります。

結論

プロジェクトや機能によって必要な方を選択して実装をしてもらうのが良いと思います。

他の機能に関して

Has One Throughなど他にも便利な機能があるので興味がある方は公式ドキュメントを見ていただければと思います。

リポジトリ

参考用にリポジトリを公開してあります。
https://github.com/Kent0129/laravel-relation-sample

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?