Laravel이 당신의 Factory 관계를 추측할 수 없는 이유
Source: Dev.to
문제
final class Client extends Model
{
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function distributor(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
$owner = UserFactory::new()->create(['name' => 'Owner']);
$distributor = UserFactory::new()->create(['name' => 'Distributor']);
$client = ClientFactory::new()
->for($owner)
->for($distributor)
->create();
Laravel은 user_id에 배포자(distributor)의 ID를 설정하고 distributor_id는 null로 남깁니다. 이는 for($model)이 모델의 클래스만 보고 변수 이름은 무시하기 때문입니다. $owner와 $distributor 모두 User 인스턴스이므로 Laravel은 첫 번째 User 관계(user)를 선택합니다.
관계 명시적으로 지정하기
두 번째 인수로 관계 이름을 전달하여 Laravel에게 어떤 관계를 사용할지 알려줍니다:
$client = ClientFactory::new()
->for($owner, 'user')
->for($distributor, 'distributor')
->create();
이제 두 외래키가 모두 올바르게 채워집니다.
대안: 외래키 직접 설정하기
키를 직접 할당하는 것이 더 명확할 때가 있습니다:
$client = ClientFactory::new()->create([
'user_id' => $owner->id,
'distributor_id' => $distributor->id,
]);
이렇게 하면 for() 호출 체인을 피할 수 있고 의도가 명확해집니다.
설계 고려사항
Laravel은 관습을 따를 때 가장 잘 동작합니다:
- 모델(
Client→User)에 대한 단일 관계는 직관적입니다. - 같은 모델에 대한 두 번째 관계를 추가하면 혼란스러울 수 있습니다. 경우에 따라 전용 모델(
Distributor)을 도입하는 것이 도메인을 더 잘 표현할 수 있습니다. - 이름이 중요합니다. 비즈니스 용어가 “owner”와 “distributor”라면 관계 이름도 그렇게 짓는 것이 인지 부하를 줄여줍니다.
Client → Customer
user → owner
명확하고 도메인에 특화된 이름은 놀라움을 줄여줍니다.
실제 예시
$address = AddressFactory::new()
->for($user)
->has(
DirectionFactory::new()
->has(
DirectionScheduleFactory::new()->count(10),
'schedules'
)
)
->create();
이 경우 for($user)가 기본적으로 동작하는데, Address에 User 관계가 하나뿐이기 때문입니다.
정리
for()는 모델 클래스와 일치하는 첫 번째 관계를 선택합니다.- 여러 관계가 존재할 때는 두 번째 인수를 사용해 정확한 관계를 지정하세요.
- 혹은 팩토리 페이로드에 외래키를 직접 설정할 수도 있습니다.
- 모델 및 관계 이름을 도메인 언어에 맞게 맞추어 혼동을 방지하세요.
- 도메인이 Laravel 관습과 어긋날 경우, 명시성이 마법보다 우선합니다.
원본 영상을 제공해 준 Joel Clermont에게 감사드립니다. 그의 Laravel 팁은 언제나 확인해 볼 가치가 있습니다.