我們?cè)陂_發(fā)的時(shí)候經(jīng)常會(huì)需要修改已經(jīng)寫好的創(chuàng)建表的migration
文件,但是又不想在開發(fā)時(shí)就寫太多的修改或者添加表字段的migration
文件,導(dǎo)致migration
文件過(guò)多,而如果直接修改了已經(jīng)創(chuàng)建好的migration
文件,那就必須要migrate:refresh
了,但是表中的測(cè)試數(shù)據(jù)重新添加又是件麻煩的事,這時(shí)候我們就可以使用laravel的數(shù)據(jù)填充功能Seeder
, 在討論這個(gè)Seeder
之前,我們先來(lái)看下如何批量生成測(cè)試數(shù)據(jù)。
laravel框架默認(rèn)引入了fzaninotto/Faker
包,這個(gè)包能讓我們快速的生成一些測(cè)試數(shù)據(jù)。包的開發(fā)思路基于Perl的Data::Faker和ruby的faker
。這個(gè)包的具體使用方式在這里https://github.com/fzaninotto/Faker,我們來(lái)看下在Laravel中如何使用它.
我們?nèi)ヅ芤粋€(gè)Laravel 5.3的框架,并且建立好數(shù)據(jù)庫(kù),并執(zhí)行掉php artisan migrate
命令。這里自己做,大家應(yīng)該是可以閉著眼睛做好這些了。
所有的model factories我們都會(huì)放在database/factories/ModelFactory.php
中,我們打開它:
<?php
/*
| Model Factories
|
| Here you may define all of your model factories. Model factories give
| you a convenient way to create models for testing and seeding your
| database. Just tell the factory how a default model should look.
| 你可以在這里定義你所有的模型工廠,使用模型工廠可以讓我們?cè)趩卧獪y(cè)試的時(shí)候很方便的使用生成
| 的測(cè)試數(shù)據(jù),同時(shí)也可以快速的將測(cè)試數(shù)據(jù)保存到我們的數(shù)據(jù)庫(kù)中。
*/
$factory->define(App\User::class, function (Faker\Generator $faker) {
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->email,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
];
});
默認(rèn)的已經(jīng)有了一個(gè)為User
模型生成測(cè)試數(shù)據(jù)的方法,這里的$faker->name,$faker->unique()->email
都是fzaninotto/Faker
包提供,上面已經(jīng)給了它的github地址,大家用的時(shí)候自己去查找下就行。
怎么使用它呢? 我們打開php artisan tinker
, 執(zhí)行
factory(App\User::class)->make();
這句話的意思是,我們會(huì)生成一個(gè)User
對(duì)象,但是我們會(huì)使用模型工廠全局幫助函數(shù)factory()
來(lái)生成它,生成的時(shí)候就給對(duì)象的所有屬性賦值。結(jié)果如下:
Psy Shell v0.8.0 (PHP 7.0.12 — cli) by Justin Hileman
>>> factory(App\User::class)->make();
=> App\User {#692
name: "Candace Bins",
email: "morar.ethan@gmail.com",
}
>>> factory(App\User::class)->make();
=> App\User {#698
name: "Prof. Alf Graham MD",
email: "mpagac@yahoo.com",
}
每調(diào)用一次都會(huì)生成一個(gè)具有不同屬性值的對(duì)象,那如果我們要同時(shí)生成多個(gè)這樣的對(duì)象呢?比如我們要生成500個(gè)User
對(duì)象,我們只要傳入第2個(gè)參數(shù)即可,如下:
factory(App\User::class, 500)->make();
通常我們會(huì)需要將這些生成的數(shù)據(jù)保存到數(shù)據(jù)庫(kù),那使用create()
即可
factory(App\User::class, 2)->create();
不過(guò)我們一般就不跑到tinker
中去生成這樣測(cè)試數(shù)據(jù)了,我們將這條語(yǔ)句些到seeds/DatabaseSeeder.php
的run
方法中:
public function run()
{
// 清空users表中已經(jīng)存在的數(shù)據(jù)
User::truncate();
factory(User::class, 2)->create();
}
然后執(zhí)行:
php artisan db:seed
就會(huì)調(diào)用上面這個(gè)run()
方法,執(zhí)行當(dāng)中的語(yǔ)句了。
不過(guò)在正式開發(fā)的時(shí)候,$faker數(shù)據(jù)要依據(jù)你的具體情況來(lái)用了,比如我們會(huì)需要一些真實(shí)的數(shù)據(jù),比如說(shuō)一些字典表,那必須是正確的數(shù)據(jù),那就會(huì)手動(dòng)指定了,所以通常我們對(duì)應(yīng)每個(gè)模型都會(huì)去寫一個(gè)Seeder
類,然后在DatabaseSeeder.php
中去調(diào)用它們,在具體的Seeder
類中去調(diào)用模型工廠,這樣代碼會(huì)方便管理很多,因?yàn)楝F(xiàn)在還沒(méi)有講到Seeder
類,所以我們現(xiàn)在知道怎么用模型工廠就可以了。
對(duì)于模型工廠的數(shù)據(jù),我們可能更多的還是用在測(cè)試中的(測(cè)試以后最后再詳說(shuō)),我們看下測(cè)試中怎么用:
我們?nèi)ソ⒁粋€(gè)posts
表,migration
文件如下:
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
比如我們要測(cè)試這個(gè)流程: 當(dāng)我訪問(wèn)post的路由的時(shí)候,給我顯示數(shù)據(jù)庫(kù)中的post的標(biāo)題和內(nèi)容.
我們直接改下tests/ExampleTest.php
中的代碼:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Post;
class ExampleTest extends TestCase
{
// 不讓測(cè)試的數(shù)據(jù)保存到數(shù)據(jù)庫(kù)中,沒(méi)有這條語(yǔ)句,當(dāng)執(zhí)行phpunit時(shí),會(huì)
// 在posts表中不斷的插入數(shù)據(jù),自己測(cè)試下
use DatabaseTransactions;
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
// 通過(guò)模型工廠生成帶有測(cè)試數(shù)據(jù)屬性的$post對(duì)象
$post = factory(Post::class)->create();
$this->visit('posts')
->see($post->title);
}
}
在database/factories/ModelFactory.php
中定義模型工廠:
$factory->define(App\Post::class, function (Faker\Generator $faker) {
return [
'title' => $faker->sentence,
'body' => $faker->paragraph
];
});
編寫路由文件,laravel 5.3路由分的很細(xì),有針對(duì)api的,針對(duì)web的,還有針對(duì)命令行的,針對(duì)web的在routes/web.php
中( 路由這樣改個(gè)人覺得很好,比5.2好多了)
Route::get('posts', function() {
return view('posts')->with('posts', App\Post::all());
});
然后去弄個(gè)resources/views/posts.blade.php
視圖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zhoujiping.com</title>
</head>
<body>
@foreach ($posts as $post)
<article>
<h2>{{ $post->title }}</h2>
<div class="body">{{ $post->body }}</div>
</article>
@endforeach
</body>
</html>
到命令行執(zhí)行phpunit
, 是綠色的
我們?cè)诨仡^來(lái)說(shuō)下fzaninotto/Faker
包, 默認(rèn)我們生成的測(cè)試數(shù)據(jù)都是英文的,如果你一定要想生成中文的測(cè)試數(shù)據(jù)(其實(shí)沒(méi)啥用),該怎么生成?回到database/factories/ModelFactory.php
在fzaninotto/Faker
源碼中我們可以看見fzaninotto/Faker
的包中的關(guān)于語(yǔ)言版本相關(guān)的都放在Provider中:
而在laravel中$faker是Faker\Generator
的是一個(gè)實(shí)例,在Faker\Generator
中有這樣一個(gè)方法:
public function addProvider($provider)
{
array_unshift($this->providers, $provider);
}
這樣一看就明白了,將需要的語(yǔ)言文件依賴注入進(jìn)來(lái)就可以了。
那我們來(lái)改下代碼:
$factory->define(App\User::class, function (Faker\Generator $faker) {
$faker->addProvider(new Faker\Provider\zh_CN\Person($faker));
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->email,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
];
});
我們到tinker中跑一下:
現(xiàn)在生成的姓名就是中文的了,但是該組件對(duì)中文的支持類太少,所以你可能會(huì)在寫Seeder
的時(shí)候用一部分$faker,用一部分手動(dòng)指定,或者自己寫一些數(shù)組,隨機(jī)插入也可以。
本節(jié)到這里結(jié)束。