Database Seeding
PHP:7.2
Laravel:5.8
在撰寫專案的測試時,最苦惱的問題莫過於還要自行在 DB 建立相關的測試資料,Laravel 為了解決這個問題,提供了 Seed
類別協助匯入測試資料。
Generating Seeders
首先,需要先透過 artisan
自動建立 seeder
檔案,此檔案將會紀錄我們匯入資料的設定:
php artisan make:seeder MemberTableSeeder
建立完成以後,就可以在 database/seeds
中發現 MemberTableSeeder.php
的檔案。
檔案裡面只會有一個 run()
的 method,當執行指令時,就會依照該 method 裡面的操作進行資料匯入。
範例
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
class MemberTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// 一次建立 10 筆
for ($i = 1; $i <= 10; $i++) {
// 透過 DB class 建立資料
DB::table('member')->insert([
'label_id' => rand(1, 100),
'name' => Str::random(10), // 產生長度 10 的字串
'password' => bcrypt('secret'), // 產生亂數密碼
'email' => Str::random(10) . '@gmail.com',
'created_at' => time()
]);
}
}
}
Notice: 產生亂數字串的使用方法在 Laravel 不同的版本中都略有差異,使用前記得先參考該版本的文件 Helpers。
Using Model Factories
除了使用 DB
class insert 資料之外,也可以使用 Factory
搭配 Eloquent Model 定義 directory 以供 Seeder
使用。
另外, Factory
是使用 Facker 這個套件協助建立測試資料,因此在資料操作上會方便許多。
建立 Factory
php artisan make:factory MemberFactory
設定 MemberFactory (database/factories)
use Faker\Generator as Faker;
use Illuminate\Support\Str;
use App\Models\Member;
$factory->define(Member::class, function (Faker $faker) {
return [
'label_id' => Label::all()->random()->id, // 搭配 Model 匯入關聯的 ID
'name' => $faker->name,
'password' => bcrypt('secret'),
'email' => $faker->unique()->safeEmail,
'created_at' => time()
];
});
Notice: 相關 Faker 操作可以參考官方文件
Setting Seeders
在設定完成以後,我們就要執行資料的匯入,artisan
預設會去執行 database/seeds/DatabaseSeeder.php
,因此我們在寫好 Seeders
後,還要在 DatabaseSeeder
控制呼叫的邏輯。
DatabaseSeeder.php
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
// 呼叫剛剛寫好的 Seeder
$this->call(MemberTableSeeder::class);
// 使用 Factory
// 一次建 50 筆資料
factory(App\Models\Member::class, 50)->create();
}
}
Import Data
當設定都完成了之後,就可以使用 artisan
進行匯入:
php artisan db:seed
# 或者可以直接指定 Seeder 匯入
php artisan db:seed --class=MemberTableSeeder
Create Relation Data
Factory
因為是搭配 Model 使用,因此也可以建立關聯性的資料。
以下例子為建立 Member
的資料時同時建立 Post
資料:
MemberFactory
use Faker\Generator as Faker;
use Illuminate\Support\Str;
use App\Models\Member;
use App\Models\Label;
$factory->define(Member::class, function (Faker $faker) {
return [
'label_id' => Label::all()->random()->id,
'name' => $faker->name,
'password' => bcrypt('secret'),
'email' => $faker->unique()->safeEmail,
'created_at' => time()
];
});
PostFactory
use Faker\Generator as Faker;
use Illuminate\Support\Str;
use App\Models\Member;
use App\Models\Post;
$factory->define(Post::class, function (Faker $faker) {
return [
'member_id' => Member::all()->random()->id,
'title' => $faker->sentence,
'content' => $faker->paragraph,
];
});
Seeder
// 注意,因為是 Relation 資料,Model 需先建立 Member -> Post 的關聯
factory(App\Models\Member::class, 50)->create()->each(function ($member) {
$member->posts()->save(factory(App\Models\Post::class)->make());
});