9
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?

More than 1 year has passed since last update.

【Laravel】ポリモフィック関連のデータの取得

Last updated at Posted at 2022-07-20

0.はじめに

前回に引き続きポリモフィック関連の記事を書きます。

今回はポリモフィック関連のデータの取得の記事になります。

1.目次

0.はじめに
1.目次
2.この記事を読んだらわかること
3.DB の確認
4.子に条件を与えた親のデータを取得
5.親に条件を与えた子のデータの取得
6.さいごに
7.参考

2.この記事を読んだらわかること

条件をもたせたポリモフィック関連のデータの取得

  • 子供側のデータの取得方法
  • 親側のデータの取得方法

3.DB の確認

テーブルの関係性

どのようなデータを使用するかは、前回の記事をご確認頂けますと幸いです。

ざっくり言うと、
commnet(子)が、video(親)と post(親)をもっている関係となります。

ER図で表すとこんな感じです

次に、DB の中はこのようになっています。

posts のデータ

id title body
1 コメントなしタイトル コメントなし本文
2 post_title1 post_body1
3 タイトル1 投稿本文1
4 post_title2 post_body2

videos のデータ

id title url
1 コメントなしタイトル http://video_title/video/1
2 video_title1 http://video_title/video/1
3 タイトル1 http://video_title/video/2
4 video_title2 http://video_title/video/3

comments のデータ

id body commentable_id commentable_type
1 コメント作成1 2 App\Models\Post
2 コメント作成2 3 App\Models\Post
3 コメント作成3 2 App\Models\Video
4 コメント作成4 3 App\Models\Video
5 コメント作成5 4 App\Models\Post
6 コメント作成6 4 App\Models\Video

4.子に条件を与えた「親のデータを取得」

以下の内容は公式ドキュメントを参考にしております。

簡単なデータの取得からいってみたいと思います。

comment(子) を持っている post(親) を取得する

まずは、親(Post)が子(comment)持っているデータを取得

use App\Models\Post;

$posts = Post::has('comments')->get();

取得したデータは、

=> Illuminate\Database\Eloquent\Collection {#4602
     all: [
       App\Models\Post {#4607
         id: 2,
         title: "post_title1",
         body: "post_body1",
       },
       App\Models\Post {#4350
         id: 3,
         title: "タイトル1",
         body: "投稿本文1",
       },
       App\Models\Post {#3990
         id: 4,
         title: "post_title2",
         body: "post_body2",
       },
     ],
   }

となます。

ここで、注意しなといけないのは、
id が 1 のデータがないことです。

これは、Post::has('comments') の通り、
comment のデータを持っている post のデータを取得しているためです。

comment(子) を持っていない post(親) は取得できません。

comment(子) に条件を与えて post(親) を取得する

comments テーブルの id が 1 を持っている post のデータを取得

use App\Models\Post;
use Illuminate\Database\Eloquent\Builder;

$posts = Post::whereHas(
        'comments',
        function (Builder $query) {
            $query->where('comments.id', '=', 1);
        }
    )->get();

取得したデータは、

=> Illuminate\Database\Eloquent\Collection {#4616
     all: [
       App\Models\Post {#4613
         id: 2,
         title: "post_title1",
         body: "post_body1",
       },
     ],
   }

となります。

comments テーブルの id が 1 を持っている post のデータを取得するコードとなります。

whereHas メソッドを使うと複雑な条件を定義することができます。

whereHas メソッドの説明

  • 第1引数には、リレーション先のテーブル名
  • 第2引数には、リレーション先の取得したいデータの条件のコールバック関数

を記述します。

それでは、comments テーブルの comment の id が 1 のデータを確認してみます。

id body commentable_id commentable_type
1 コメント作成1 2 App\Models\Post

commentable_id が 2
commentable_type が App\Models\Post
となっています。

これは、親が何かを表しています。

  • commentable_id は、親の id
  • commentable_type は、親のタイプ(※ Model の情報)

を示しています。

なので、

comments テーブルの id が 1 、post テーブル の id が 4
のデータを持っているということを示しています。

posts の id が4 のデータは、

id title body
2 post_title1 post_body1

となっており、取得したデータとテーブルが一致していることがわかるかと思います。

5.親に条件を与えた「子のデータの取得」

それでは、次に子側のデータの取得に方法に入りたいと思います。

post(親) や video(親) に条件を与えた comment(子) を取得する

ポリモフィック関連の親(post や video)に条件を与えた子(comment)のデータの取得

早速、コードを見てみましょう。


use App\Models\Comment;
use App\Models\Post;
use App\Models\Video;
use Illuminate\Database\Eloquent\Builder;

$comments = Comment::whereHasMorph(
        'commentable',
        [Post::class, Video::class],
        function (Builder $query) {
            $query->where('title', '=', 'タイトル1');
        }
    )->get();

取得したデータは、

=> Illuminate\Database\Eloquent\Collection {#4613
     all: [
       App\Models\Comment {#4597
         id: 2,
         body: "コメント作成2",
         commentable_id: 3,
         commentable_type: "App\Models\Post",
       },
       App\Models\Comment {#4611
         id: 4,
         body: "コメント作成4",
         commentable_id: 3,
         commentable_type: "App\Models\Video",
       },
     ],
   }

となります。

これは、
親の Post と Video の title カラムが タイトル1 を持っている子の Comment を取得しています。

ポリモフィック関連で親に条件を持たすことができているのは、
whereHasMorph メソッドになります。

whereHasMorph メソッドの説明

  • 第1引数には、CommentModel で定義したポリモフィック先のデータを取得するメソッド
    Laravel でポリモフィック関連の Factory を作成してみた参照)
  • 第2引数には、ポリモフィック関連の親のクラス
    ※ 今回は、複数の親のデータを取得しているが、単数の親でも問題ありません。
      ただ単数の場合は、array 型ではなく、string 型でOKです。
  • 第3引数には、リレーション先の取得したいデータの条件のコールバック関数

を記述しています。

title カラムが タイトル1 を持っている Post::class, Video::class は、下記のとおりです。

Post::class

id title body
3 タイトル1 投稿本文1

Video::class

id title url
3 タイトル1 http://video_title/video/2

上記のデータを持っている comment は

id body commentable_id commentable_type
2 コメント作成2 3 App\Models\Post
4 コメント作成4 3 App\Models\Video

となっており、取得したデータとテーブルが一致していることがわかるかと思います。

commentable_id が 親の Post::class, Video::class の id 、
commentable_type が Post::class, Video::class を示しています。

6.さいごに

ポリモフィック関連先の条件にコールバック関数をつかっているので複雑に感じましたが、
「どこから」「どんな条件」でデータを取得するかの基本が掴めていたら理解することができるのかなと感じました。

とか言いつつ、私自身もこれを理解するのに時間がかかりました。

今回は、条件は1つしかありませんが、
コールバック関数内で複数の条件をもたせて、もっと複雑な処理をすることができます。

7.参考

9
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
9
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?