【Laravel 9】Eloquent 便利なクエリビルダ

Laravel9の便利そうなクエリビルダを調べていて、実用的なものをまとめました。

https://readouble.com/laravel/9.x/ja/eloquent-relationships.html

## has 
リレーション先にレコードがあるレコードのみ取得
```php
// commentが少なくとも1つ以上あるすべてのpostを取得
$posts = Post::has('comments')->get();
```
## whereRelation
リレーション先のテーブルでwhereをすることができます。
複数の条件を指定したい場合は`whereHas()`を使用します。
```php
// users → companies.name === $name のユーザーのみ取得
$users = User::whereRelation('company', 'name', $name)->get();
```
## orWhereRelation
`orWhere`のRelation版です。
```php
// users → companies.name === $name or companies.address === $address のユーザーのみ取得
$users = User::whereRelation('company', 'name', $name)
    ->orWhereRelation('company', 'address', $address)
    ->get();
```
## whereHas
リレーション先のテーブルで、複数の条件を指定することができます。
```php
// users → companies.name === $name and companies.address === $address のユーザーのみ取得
$users = User::whereHas('company', function ($query) use ($name, $address) {
    $query->where('name', $name)
        ->where('address', $address);
})->get();
```

## doesntHave
指定したリレーション先のレコードが存在しないレコードのみに絞り込むことができます。
条件を指定したい場合は`whereDoesntHave()`を使用します。
```php
// 紐づくpostsのレコードがないユーザーのみを取得
$users = User::doesntHave('posts')->get();
```

## whereDoesntHave
whereHasの逆で、不一致のレコードを取得します。
```php
// 紐づくposts.title === $titleのレコードがないユーザーのみを取得
$users = User::whereDoesntHave('posts', function ($query) {
    $query->where('title', $title);
})->get();
```

## with
リレーション先のレコードを取得します。
`AS`は使用できません。
```php
// users → postsのデータが取得される
$users = User::with('posts')->get();
```

### withのオプション
#### 複数指定
```php
// users → posts, users → companyのデータが取得される
$users = User::with(['posts', 'company'])->get();
```

#### 取得するレコードの条件指定
```php
// postsはapprovedがfalseのレコードのみ取得される
$users = User::with([
    'company',
    'posts' => function ($query) {
        $query->where('approved', false);
    }
])->get();
```

#### .(ドット)区切りで孫のレコードも取得
```php
// users → posts → commentsのデータが取得される
$users = User::with('posts.comments')->get();
```
#### ネストした孫のレコードを複数取得
```php
// users → posts → comments,detailsのデータが取得される
$users = User::with(
    [
        'posts' => [
            'comments',
            'details'
        ]
    ]
)->get();
```

#### :でselectをする
```php
// postsはidとtitleしか取得されない
$users = User::with('posts:id,title')->get();
```


#### :でselectをする
```php
// postsはidとtitleしか取得されない
$users = User::with('posts:id,title')->get();
```


## withCount
リレーション先テーブルのレコード数を生成してくれます。
複数指定することも可能です。
```php
// posts_countというプロパティ名で、postsのカウントが取得されます。
$users = User::withCount('posts')->get();
echo $users[0]->posts_count;

// posts_countとpending_posts_countが取得されます。
$users = User::withCount(
    [
        'posts',
        'posts AS pending_posts_count'  => function ($query) {
            $query->where('approved', false);
        }
    ]
)->get();
echo $users[0]->posts_count;
echo $users[0]->pending_posts_count;
```

## 常にwithロードするテーブルを指定
Modelの$withを指定することで、常にロードするテーブルを指定できます。
```php
class User extends Model
{
    /**
     * 常にロードする必要があるリレーション
     *
     * @var array
     */
    protected $with = ['permission'];
    
    public function permission()
    {
        return $this->HasOne(Permission::class);
    }
}
```

このようにして、$withから一時的に外すことが可能です。
```php
$users = User::without('permission')->get();
```