本記事は、Laravelでリレーション先を基準に並び替えをする方法を紹介します。
イメージ
この記事を書く背景
学習者へアドバイスやサポートする立場のお仕事に携わっているなかで、 このような質問がありました。
投稿一覧をユーザー名で並び替えを行いたい。
whereHasでリレーション先の並び替えを行っているのに上手く表示されません。
なぜでしょうか?
試していたソースコードは下記となります。
$posts = Post::whereHas('user', function($query){ $query->orderBy('id', 'asc' ); })->get();
原因は
リレーション先テーブルの中で並び替えを行っているだけなので、抽出されるデータには変わりありません。
ではどうすればリレーション先を基準に並び替えができるのか?
どのようなクエリ文が発行されているか?
whereHasはどいうときに使用されるのか?
シンプルな具体例に沿って確認していきたいと思います
確認のための準備
テーブルとデータは下記のように用意しました。
usersテーブル
postsテーブル
Userモデルに関してはデフォルトのものを使用します。
もしPostテーブルを作成からテストデータ挿入方法を学びたい方はこちらの記事を参考にして下さい!
テーブルとデータが作成されたらModelファイルにリレーションを定義します。
Models/Post.php
//省略 public function user() { $this->belongsTo(App/Models/User::class); } //省略
Postテーブルから見ると多対1の関係となります。
登録された投稿を一覧表示するためのソースコードを用意します。 index.blabe.php
<table style="margin: 30px auto 0;" border=3> <tr> <th>投稿ID </th> <th>ユーザー名</th> <th>投稿内容</th> </tr> @foreach ( $posts as $post ) <tr> <td style="text-align: center"> {{ $post->id }} </td> <td> {{ $post->user->name }} </td> <td> {{ $post->body }} </td> </tr> @endforeach </table>
一覧を表示させる為のシンプルなコードです。
bladeへ渡す変数を下記のように
PostController.php
use App\Models\Post; class PostController extends Controller { public function index() { \\ここに記述を書いていきます。 return view('admin.post.index', compact('posts')); } }
それでは準備が整ったので順番に見ていきます。
まずは普通に一覧表示
$posts = Post:all();
結果
whereHas
$posts = Post::whereHas('user', function($query){ $query->orderBy('id', 'asc'); })->get();
結果
結果は変わりありません。
どのようなSQLが発行されているかtoSql()メソッドで確認したいと思います。
$posts = Post::whereHas('user', function($query){ $query->orderBy('id', 'asc'); })->toSql(); dd($posts);
結果
select * from `posts` where exists (select * from `users` where `posts`.`user_id` = `users`.`id` order by `id` asc)
whereの中でサブクエリで並び替えを行っているだけで、呼び出しているデータはpostsデータとなるので、 並び替えに影響しません。
例えば、idが3のみのユーザーで絞り込みを行いたい場合はwhereHasの出番です。
$posts = Post::whereHas('user', function($query){ $query->where('id', 3); })->get();
結果
SQLはこちらとなります。
select * from `posts` where exists (select * from `users` where `posts`.`user_id` = `users`.`id` and `id` = 3)
ユーザーid で絞込みをしてから、存在するデータのみを呼び出しています。
リレーションを条件に並び替え
では冒頭の本題です。 最初に記述方法を記載します。
$posts = Post::select('*') ->join('users','posts.user_id','=','users.id') ->orderBy('users.name','asc') ->get();
Eloquentのクエリビルダを使用します。
SQLはこちらです。
select * from `posts` inner join `users` on `posts`.`user_id` = `users`.`id` order by `users`.`name` asc
join()でpostテーブルのidとuser_idを紐づけたことによって、user_idを並び替えるとidが並び変わります。
結果
思った通りの結果となりました。
お疲れ様でした!
「参考になったー✌」という方は下の方にある星マークを押してもらえると喜びます。 またTwitterのフォローしてもらえると幸いです!