目次
こんにちは!ともです(@_tomo_engineer)!
この記事ではLaravelでリレーション先の情報を元にクエリを発行し、絞り込む方法についてのまとめます。
Laravel5.5では確認済みです!
目次
- 想定するテーブルと条件について
- リレーション先の情報を元にクエリの作成
- その他の手段
想定するテーブルについて
hasManyの関係にあるテーブルを想定します。
usersテーブルとpostsテーブルを考えます。
ある投稿者(user)が複数の投稿(post)を行う、Twitterにありそうな投稿テーブルです。
- users_table
id | name | created_at |
1 | 田中 | 2018-09-01 |
2 | 鈴木 | 2018-09-02 |
3 | 山田 | 2018-09-03 |
- posts_table
id | user_id | content | created_at |
1 | 1 | 田中の投稿1 | 2018-09-02 09:00 |
2 | 1 | 田中の投稿2 | 2018-09-03 21:00 |
3 | 1 | 田中の投稿3 | 2018-09-04 19:00 |
4 | 2 | 鈴木の投稿1 | 2018-09-02 08:00 |
5 | 3 | 山田の投稿1 | 2018-09-05 19:00 |
users_tableのidとposts_tableのuser_idによって紐ついており、hasManyの関係にあるレコードを同一の色で示しています。
ここで、次のようなクエリを発行したいと考えます。
2018年9月3日0時00分以降に投稿したユーザを取得したい
今回の場合ですと
id | user_id | content | created_at |
1 | 1 | 田中の投稿1 | 2018-09-02 09:00 |
2 | 1 | 田中の投稿2 | 2018-09-03 21:00 |
3 | 1 | 田中の投稿3 | 2018-09-04 19:00 |
4 | 2 | 鈴木の投稿1 | 2018-09-02 08:00 |
5 | 3 | 山田の投稿1 | 2018-09-05 19:00 |
上記の緑色の投稿が2018年9月3日0時00分以降の投稿ですので、user_id = 1, 3の
ユーザが検索に引っかかる訳です。
ControllerとModel
- web.php
Route::get('/', 'IndexController@index');
- IndexController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class IndexController extends Controller
{
public function index(){
return view('home');
}
}
- User.php(モデル)
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function posts(){
return $this->hasMany('App\Post', 'user_id', 'id');
}
}
では次に、どのように検索するかについてご説明致します。
リレーション先の情報を元にクエリの生成
リレーション先の情報を利用してクエリを発行したい場合、whereHasが利用できます。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class IndexController extends Controller
{
public function index(){
$user = User::whereHas('posts', function($query){
$query->where('created_at', '>', '2018-09-03');
})->get();
dd($user);
return view('home');
}
}
Userモデルで作成したリレーションはpostsでしたので、第一引数にposts
第二引数ではposts_tableを見た際のクエリです。
ですので、この場合のcreated_atはposts.created_atを意味しています。
ddメソッドで確認した結果は以下です。

田中・山田の2名を取得する事ができました。
array[0]が田中さん、arrayが山田さんです。
その他の手段
Laravelの上手く使えばできるんだろうけど、その方法が分からない・・・
そのような場合はクエリビルダでSQLを作成するという手段で乗り切ります。
今回の場合ですと、テーブルの結合を行います。
users_tableのidとposts_tableのuser_idでjoinを行う事で検索する事ができます。
- クエリビルダで
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class IndexController extends Controller
{
public function index(){
$users = User::
join('posts', 'users.id', 'posts.user_id')
->where('posts.created_at', '>', '2018-09-03')
->select('users.*')
->distinct()
->get();
return view('home');
}
}
これにより、users_tableとposts_tableがuser_idを介して接続されたテーブルを作成し後は単純に検索を行うだけです。
ここで注意点はこのテーブルにはcreated_atが2つ存在するという事です。
- users_tableのcreated_at
- posts_tableのcreated_at
単純にcreated_atと書くと曖昧(ambiguous)となります。
ですので、
- users.created_at => usersのcreated_at
- posts.created_at => postsのcreated_at
とどちらのテーブルのカラムを指すのか明示する必要があります。
まとめ
今回はLaravel5.5でリレーション先の情報を利用してクエリを発行する方法を書きました。
whereHasを利用した方法と、クエリビルダを利用する方法をについて書きました。
下記のLaravel ドキュメントで確認して見ましょう。
- リレーションについて
https://readouble.com/laravel/5.5/ja/eloquent-relationships.html
- クエリビルダについて
https://readouble.com/laravel/5.5/ja/queries.html