特定カラムの値によって Eager Loading の動作を変える
- ユーザを表す
User
モデルがある - 会社を表す
Company
モデルがある - 学校を表す
School
モデルがある - ユーザの職業を表す
$user->job
フィールドがある -
$user->job
の値によって Eager Load するリレーションを分岐させたい$user->job === 'office_worker'
の場合には$user->company
リレーションを読み込む$user->job === 'student'
の場合には$user->school
リレーションを読み込む
こういう場合には,コレクションクラスを自作します。
app/Collections/UserCollection.php
<?php
declare(strict_types=1);
namespace App\Collections;
use App\User;
use Illuminate\Database\Eloquent\Collection;
class UserCollection extends Collection
{
/**
* 所属している組織を Eager Load します。 job フィールドの値によって振り分けられます。
*
* @return $this
*/
public function loadOrganization(): self
{
$this->groupBy(
function (User $user) {
return $user->job;
}
)->each(
function (self $users) {
switch ($users->first()->job) {
case 'office_worker':
return $users->load('company');
case 'student':
return $users->load('school');
}
}
);
return $this;
}
}
app/User.php
class User extends Model
{
public function newCollection(array $models = []): UserCollection
{
return new UserCollection($models);
}
public function company(): BelongsTo
{
return $this->belongsTo(Company::class);
}
public function school(): BelongsTo
{
return $this->belongsTo(School::class);
}
}
// ユーザを取得
$users = User::whereIn('job', ['office_worker', 'student'])->get();
// 職業の種類が1種類のときは1クエリで済む
// (2種類の場合は2クエリ必要)
$users->loadOrganization();
ちょっと例があんまり良くないけどたまに使いたくなるテクニック