03강: Faker 한국어 팩토리 & 1,000권 도서 데이터 생성 공장
실습 프로젝트: 지니샵(JinyShop) 온라인 도서 쇼핑몰
주제: Eloquent Model Factory, Faker 한국어 로케일, 현실적인 도서/저자/출판사 데이터 공장 및 팩토리 상태(State)
등장인물: 🐱 지니(시니어 멘토), 👧 도로시(주니어 개발자), 🐶 토토(개발 보조견)
공식 문서 연계: Eloquent 팩토리 (Eloquent Factories)
💬 1. 지니와 도로시의 티키타카 회의
👧 도로시: “지니! 데이터베이스 테이블은 멋지게 만들었는데, 개발하고 테스트하려면 책 데이터가 수백, 수천 권은 들어있어야 페이지네이션도 시험하고 검색 기능도 테스트할 수 있잖아요! 수작업으로 1,000권의 책 제목과 ISBN, 가격을 엑셀로 치려면 일주일도 모자라요!”
🐱 지니: “후후, 도로시! 현대의 라라벨 개발자는 절대 손으로 데이터를 입력하지 않는단다. 우리에겐 Eloquent 모델 팩토리(Model Factory)와 Faker 데이터 생성 엔진이라는 자동화 공장이 있거든! 단 3초 만에 그럴듯한 한국어 책 제목, 13자리 고유 ISBN 번호, 저자 소개글을 가진 1,000권의 도서 데이터를 번개처럼 찍어낼 수 있단다!”
🐶 토토: “멍멍! 팩토리에 ->ebook(), ->discounted() 같은 상태(State) 메서드를 붙여두면 ‘20% 할인된 전자책’ 같은 특수 조건 데이터도 레고처럼 뚝딱 만들 수 있다멍!”
🎯 2. 실습 목표 및 서점 시나리오
Publisher,Author,Category,Book모델과 팩토리 파일을 한 번에 생성합니다.- Faker 라이브러리를 활용해 현실적인 한국어 책 제목, ISBN-13, 가격, 출간일을 정의합니다.
- 팩토리 상태(State) 메서드로 ‘베스트셀러’, ‘할인 도서’, ‘품절 도서’ 분기를 구현합니다.
🛠️ 3. 단계별 실습 절차 (Step-by-Step)
[Step 1] 모델과 팩토리 파일 일괄 생성
아티산의 -f 옵션을 주면 모델 생성과 동시에 팩토리 클래스를 짝지어 만들어 줍니다:
php artisan make:model Publisher -f
php artisan make:model Author -f
php artisan make:model Category -f
php artisan make:model Book -f
[Step 2] 팩토리 정의 작성
1) 출판사 팩토리 (database/factories/PublisherFactory.php)
public function definition(): array
{
$publishers = ['지니서적', '도로시미디어', '토토북스', '위키북스', '인사이트', '한빛미디어', '에이콘출판', '길벗'];
$name = fake()->unique()->randomElement($publishers) ?? fake()->company().'출판사';
return [
'name' => $name,
'code' => 'PUB-'.fake()->unique()->numerify('####'),
'contact_email' => fake()->safeEmail(),
'website_url' => fake()->url(),
];
}
2) 저자 팩토리 (database/factories/AuthorFactory.php)
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'bio' => fake()->realText(120),
'profile_photo_url' => 'https://i.pravatar.cc/150?u='.fake()->uuid(),
];
}
3) 도서 핵심 팩토리 (database/factories/BookFactory.php)
namespace Database\Factories;
use App\Models\Author;
use App\Models\Category;
use App\Models\Publisher;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class BookFactory extends Factory
{
public function definition(): array
{
$prefixes = ['초보자를 위한', '실전', '우아한', '핵심만 골라 배우는', '러닝', '한 권으로 끝내는'];
$topics = ['라라벨 13 프로그래밍', '모던 PHP 아키텍처', '클라우드 인프라 구축', '도커와 쿠버네티스', '알고리즘과 자료구조', 'TDD 테스트 자동화', '데이터베이스 쿼리 최적화'];
$title = fake()->randomElement($prefixes).' '.fake()->randomElement($topics).' #'.fake()->numberBetween(1, 99);
$price = fake()->numberBetween(15, 60) * 1000; // 15,000원 ~ 60,000원
return [
'isbn' => fake()->unique()->isbn13(),
'title' => $title,
'slug' => Str::slug($title).'-'.fake()->randomNumber(4),
'author_id' => Author::factory(),
'publisher_id' => Publisher::factory(),
'category_id' => Category::factory(),
'price' => $price,
'sale_price' => null,
'stock_quantity' => fake()->numberBetween(10, 500),
'format' => fake()->randomElement(['paperback', 'hardcover', 'ebook']),
'page_count' => fake()->numberBetween(200, 800),
'published_at' => fake()->dateTimeBetween('-3 years', 'now')->format('Y-m-d'),
'description' => fake()->realText(300),
'status' => 'published',
];
}
/**
* 상태 1: 할인 중인 도서
*/
public function discounted(int $percent = 10): static
{
return $this->state(fn (array $attributes) => [
'sale_price' => (int) ($attributes['price'] * (1 - $percent / 100)),
]);
}
/**
* 상태 2: 전자책(eBook)
*/
public function ebook(): static
{
return $this->state(fn (array $attributes) => [
'format' => 'ebook',
'stock_quantity' => 99999, // 전자책은 무제한 재고
'ebook_file_path' => 'ebooks/'.fake()->uuid().'.epub',
]);
}
/**
* 상태 3: 품절 도서
*/
public function outOfStock(): static
{
return $this->state(fn (array $attributes) => [
'stock_quantity' => 0,
'status' => 'out_of_stock',
]);
}
}
[Step 3] Tinker에서 실시간 팩토리 생성 테스트
터미널에서 php artisan tinker를 열고 팩토리가 정상 동작하는지 테스트합니다:
php artisan tinker
// 단 한 권의 책과 연관 저자/출판사/카테고리 즉석 생성
App\Models\Book::factory()->discounted(20)->create();
// 생성된 책 확인
App\Models\Book::first();
결과:
=> App\Models\Book {#6012 id: 1, isbn: "9780201633610", title: "실전 모던 PHP 아키텍처 #42", price: 32000, sale_price: 25600, format: "paperback", ... }
🔍 4. 라라벨 공식 문서 원리 심층 분석 (Deep Dive)
팩토리의 연관 관계 자동 해결 (Sub-factories)
BookFactory의 정의를 보면'author_id' => Author::factory()처럼 적혀 있습니다.- 개발자가 저자(Author)를 따로 넘겨주지 않아도, 라라벨이 알아서
Author레코드를 먼저 생성하고 그 ID 값을author_id에 외래키로 채워 넣습니다! - 만약 기존 저자를 재사용하고 싶다면
Book::factory()->for($existingAuthor)->create()처럼 지정할 수도 있습니다.
🐶 5. 토토의 트러블슈팅 & 주의사항
🐶 토토의 멍멍 가이드!
- 한국어 이름 대신 영문 이름(John Doe)이 나와요!
config/app.php의'faker_locale' => env('APP_FAKER_LOCALE', 'ko_KR')설정을 확인하라멍!.env파일에APP_FAKER_LOCALE=ko_KR을 적어두면 홍길동, 김철수 같은 친근한 한국어 이름이 나온다멍!
💡 6. 3강 자가진단 과제
tinker에서Book::factory()->count(10)->ebook()->create();를 실행하여 전자책 10권이 생성되는지 확인하세요.Book::where('format', 'ebook')->count();로 정확히 10권이 조회되는지 검증하세요.