0
0

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 5 years have passed since last update.

Laravelのhas()で詰まった

Posted at

はじめに

ログインしている user に、 group とのリレーションが存在するか確認したい。
$user->has('groups')->exists() でうまく動くかと思ったが期待する挙動ではなかった。
has()の挙動がよくわからない。どのような場合に自分が期待する挙動になるのか調べてみた。

ERD

alt

試したこと

1. Modelからhasメソッドを呼び出す

\Auth::user()->has('groups')->exists()
前述した通り、期待する挙動をしない。
sqlを確認すると、Auth::user()のidを考慮していない。
そのため、いずれかのuserレコードにgroupsとのリレーションが存在すればtrueを返してしまう。

select exists(
    select * from `users` where exists (
        select * from `groups` inner join `user_group` on `groups`.`id` = `user_group`.`group_table_id` 
        where `users`.`id` = `user_group`.`user_table_id`
    )
) as `exists`

2. 中間テーブルを使用しないリレーションで試す

\Auth::user()->has('gmbLocations')->exists();
期待する挙動をしない。
1と同様にModelからhasメソッドを呼び出す。
中間テーブルを挟んでいるのがよくないのかと思って試してみたが1と同じくAuth::user()のidが考慮されない。

select exists(
    select * from `users` where exists (
        select * from `posts`
        where `users`.`id` = `posts`.`user_table_id`
    )
) as `exists`

3. QueryBuilderからhas()メソッドを呼び出す

UserModel::where('id', \Auth::id())->has('groups')->exists()
期待通りの挙動をする。
sqlは1にAuth::user()のidを考慮するための where users.id = ? を追加したものになっている。
Modelのhas()とQueryBuilderのhas()では挙動が異なっていそう。

select exists(
    select * from `users` where `users`.`id` = ? and exists (
        select * from `groups` inner join `user_group` on `groups`.`id` = `user_group`.`group_table_id` 
        where `users`.`id` = `user_group`.`user_table_id`
    )
) as `exists`

4. hasメソッドを使わずにリレーションメソッドを利用する

\Auth::user()->groups()->exists()
期待通りの挙動をする。
コードもsqlもシンプルでわかりやすい。

select exists(
    select * from `groups` inner join `user_group` on `groups`.`id` = `user_group`.`group_table_id` 
    where `user_group`.`user_table_id` = ?
) as `exists`

まとめ

  • QueryBuilderとModelのhas()は挙動が異なるよう
  • Modelにリレーションが存在するか確かめるにはModel->relationTable()->exists()
  • QueryBuilderにリレーションが存在するか確かめるにはBuilder->has('relationTable')->exists()
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?