라라벨로 배우는 실전 PHP 웹 프로그래밍
PART 1 라라벨 입문
11. 데이터베이스 시딩
데이터베이스 테이블에 데이터를 심는 행위를 시딩이라고 한다.
시딩은 서비스 구성에 필요한 기본 데이터, 개발 중에 필요한 데이터, 테스트를 위한 데이터를 빠르게 준비할 때 사용한다. 그리고 라라벨은 클래스 문법으로 데이터 시딩을 자동화할 수 있는 방법을 제공한다.
11.1 시더 만들기
시더 클래스 뼈대 코드 만들기
1
2
$ php artisan make:seeder UsersTableSeeder
Seeder created successfully.
방금 만든 시더 클래스는 database/seeds 디렉터리 아래에 있다. 파일을 열어서 내용을 채워보자
database/seeds/UsersTableSeeder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
use Illuminate\Database\Seeder;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
App\User::create([
'name' => sprintf('%s %s',str_random(3),str_random(4)),
'email' => str_random(10).'@example.com',
'password' => bcrypt('password'),
]);
}
}
시더 클래스의 이름은 자유롭게 지을 수 있다. 아티즌의 시딩 명령이 시더 클래스의 run() 메서드를 실행한다. 따라서 시딩 로직을 run() 안에 넣어야 한다.
- str_random(int $length = 16)
라라벨 도우미 함수. $length 바이트짜리 랜덤 문자열을 반환한다. - sprintf(string $format, mixed $args = null)
php 내장함수. sprintf 함수 대신 str_random(3).’ ‘.str_random(4)와 같이 바꾸어 쓸 수 있다.
이제 아티즌 멸령줄로 시딩을 하고, 데이터베이스에서 결과를 확인한다.
데이터베이스 시더 실행
1
2
$ php artisan db:seed --class=UsersTableSeeder
Database seeding completed successfully.
11.2 모델 팩토리
모델 팩토리는 더미 데이터를 빠르게 만들기 위한 도구다. 팅커 콘솔로 모델 팩토리를 이용해 보자.
모델 팩토리 맛보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ php artisan tinker
Psy Shell v0.9.12 (PHP 7.3.11 — cli) by Justin Hileman
>>> factory(App\User::class)->make();
=> App\User {#3198
name: "Jefferey Pouros",
email: "helga.will@example.net",
email_verified_at: Illuminate\Support\Carbon @1612358212 {#3194
date: 2021-02-03 13:16:52.342677 UTC (+00:00),
},
}
>>> factory(App\User::class)->make(['name'=>'Foo']);
=> App\User {#3207
name: "Foo",
email: "brad.schowalter@example.com",
email_verified_at: Illuminate\Support\Carbon @1612358244 {#3208
date: 2021-02-03 13:17:24.870220 UTC (+00:00),
},
}
>>>
위 명령은 실행할 때마다 다른 값을 출력한다.
factory(string $class, int $amount = 1)는 도우미 함수다. $amount 인자는 생략할 수 있다. $amount 인자를 쓰면 지정된 수 만큼의 $class 인스턴스를 만든다.
make(array $attributes = []) 메서드는 모델 팩토리가 임의로 채운 값을 이용해서 새로운 모델 인스턴스를 만든다. $attributes 인자를 넘기면 임의 값을 오버라이드할 수 있다
11.2.1 시더 수정
make() 메서드는 모델 인스턴스를 만들기만 한다. 모델을 데이터베이스에 저장하려면 create(array $attributes = []) 메서드를 사용한다. 모델 팩토리를 이용하여 앞서 만든 시더 클래스를 수정하다.
database/seeds/UsersTableSeeder.php ```php <?php
use Illuminate\Database\Seeder;
class UsersTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { factory(App\User::class, 5)->create(); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
아티즌 명령줄로 시딩을 하면(php artisan db:seed) users 테이블에 다섯 명의 새로운 사용자가 만들어진다.
#### 11.2.2 모델 팩토리 추가
모덾 팩토리는 users 테이블 스키마를 어떻게 알았을까? 프레임워크 어딘가에서 모델 팩토리를 선언하고 있지는 않을까? 혹 여러분의 모델 팩토리가 아래와 다르다면 반드시 수정하기 바란다.
> database/factories/UserFactory.php
```php
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\User;
use Illuminate\Support\Str;
use Faker\Generator as Faker;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->safeEmail,
'password' => bcrypt('password'), // password
'remember_token' => Str::random(10),
];
});
ModelFactory.php, $factory
이 파일은 라우팅 정의처럼 다른 클래스가 참조하기 위해 사용하는 파일이다. 이 파일에는 $factory라 변수가 이미 선언되어 있다. 이 변수는 Illuminate\Database\Eloquent\Factory 클래스의 인스턴스라 define(string $class, callable $attribute ) 메서드를 쓸 수 있다. define() 메서드의 첫 번째 인자는 모델 이름이며, 두 번쩨 인자는 콜백이다.$faker
콜백은 Faker\Generator $faker 인스턴스를 인자로 받고 배열을 반환한다. 콜백 안에서는 인자로 받은 $faker 변수의 메서드를 이용해서 모델 프로퍼티에 채울 임의의 값을 연관 배열로 만들어 반환한다. $faker 의 메서드들은 fzaninotto/faker 문서에서 확인할 수 있다(이 컴포넌트는 composer.json에 의존성으로 선언되어 있다.)Article 모델 팩토리를 정의하고 새로운 시더를 만들자. user_id 열이 없다는 점을 눈여겨보자. 아래의 코드를 보면 $faker->dateTimeThisMonth;는 그 뜻을 직관적으로 알 수 있다.
database/factories/UserFactory.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\User;
use Illuminate\Support\Str;
use Faker\Generator as Faker;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->safeEmail,
'password' => bcrypt('password'), // password
'remember_token' => Str::random(10),
];
});
$factory->define(App\Article::class, function (Faker $faker) {
$date = $faker->dateTimeThisMonth;
return [
'title' => $faker->sentence(),
'content' => $faker->paragraph(),
'created_at' => $date,
'updated_at' => $date,
];
});
articles 테이블 시더 뼈대 코드 만들기
1
2
$ php artisan make:seeder ArticlesTableSeeder
Seeder created successfully.
database/seeds/ArticlesTableSeeder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
use Illuminate\Database\Seeder;
class ArticlesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$users = App\User::all();
$users->each(function($user){
$user->articles()->save(
factory(App\Article::class)->make()
);
});
}
}
- $users->each( … ); 모델 팩토리에 user_id 정의가 없으므로 사용자와의 관계를 이용해서 포럼 글을 만든다. $users 변수에 사용자 컬렉션을 담고, 컬렉션을 순회하면서 포럼 글을 만드는 식으로 짰다. 엘로퀀트 컬렉션에서 쓸 수 있는 each 메서드를 이용했는데, foreach($users as $user){ … } 를 사용해도 무방하다.
- $user->articles()->save( … ); make() 메서드는 새로운 모델 인스턴스를 반환하고 데이터베이스에 저장하지는 않는다. 방금 만든 모델 인스턴스는 sava(\Illuminate\Database\Eloquent\Model $model) 메서드의 인자로 대입되었다. save() 메서드는 create(array $attributes = []) 와 같은 일을 하는데, 받을 수 있는 인자의 타입만(객체와 배열) 다르다.
11.3 마스터 시더
모델마다 아티즌 시딩 명령을 수행하는 것은 번거롭다. 라라벨은 시더 클래스를 등록할 수 있는 마스터 시더 클래스를 제공한다. 이 레지스트리가 필요한 이유는 시딩의 순서 때문이다. 마이그레이션할 때 외래 키와 연결할 다른 테이블의 열이 없으면 오류가 발생했다. 시딩도 마찬가지다.
database/seeds/DatabaseSeeder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
if (config('database.default') !== 'sqlite'){
DB::statement('SET FOREIGN_KEY_CHECKS=0');
}
App\User::truncate();
$this->call(UsersTableSeeder::class);
App\Article::truncate();
$this->call(ArticlesTableSeeder::class);
if (config('database.default') !== 'sqlite'){
DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
}
}
아티즌 명령중로 시딩하고, 테이블에서 결과를 확인하자.
데이터베이스 시딩
1
2
3
4
$ php artisan db:seed
Seeding: UsersTableSeeder
Seeding: ArticlesTableSeeder
Database seeding completed successfully.
config(‘database.default’)
mysql을 반환한다. config/database.php 파일에서 default 키에 할당된 값을 읽어오는 구문이다.
데이터베이스 마이그레이션에서 FOREIGN_KEY_CHECKS를 본 적이 었다. 데이터를 변경 할 때 외래 키 체크를 잠시 꺼두기 위한 데이터베이스 구문이다. SQLite 데이터베이스는 이 구문을 지원하지 않기 때문에 예외 처리한 것이다. FOREIGN_KEY_CHECKS 설정을 끄지 않고 시딩을 실행하면 Illuminate\database\QureyException 이 발생한다. 시딩이 끝났으면 다시 켜야 한다truncate() 이 메서드는 테이블에 담긴 모든 데이터를 버린다. 데이터를 지운다는 측면에서 delete()메서드와 같지만, 이 메서드는 기본 키를 1부터 재배열한다는 점이 다르다.
call(string $class) 이 메서드는 $class::run() 메서드의 본문을 실행하고 콜솔에 결과를 출력한다. call() 메서드는 부모 클래스에서 찾을 수 있다.
11.4 마이그레이션과 시딩
마이그레이션과 시딩 한 번에 실행하기
1
$ php artisan migrate:refreshh --seed
Comments powered by Disqus.