我們?cè)陂_(kāi)發(fā)的時(shí)候經(jīng)常會(huì)需要修改已經(jīng)寫(xiě)好的創(chuàng)建表的migration
文件,但是又不想在開(kāi)發(fā)時(shí)就寫(xiě)太多的修改或者添加表字段的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ù)。包的開(kāi)發(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
中,我們打開(kāi)它:
<?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í)候自己去查找下就行。
怎么使用它呢? 我們打開(kāi)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ò)在正式開(kāi)發(fā)的時(shí)候,$faker數(shù)據(jù)要依據(jù)你的具體情況來(lái)用了,比如我們會(huì)需要一些真實(shí)的數(shù)據(jù),比如說(shuō)一些字典表,那必須是正確的數(shù)據(jù),那就會(huì)手動(dòng)指定了,所以通常我們對(duì)應(yīng)每個(gè)模型都會(huì)去寫(xiě)一個(gè)
Seeder
類(lèi),然后在DatabaseSeeder.php
中去調(diào)用它們,在具體的Seeder
類(lèi)中去調(diào)用模型工廠,這樣代碼會(huì)方便管理很多,因?yàn)楝F(xiàn)在還沒(méi)有講到Seeder
類(lèi),所以我們現(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
中的代碼:
<?phpuse 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 ];});
編寫(xiě)路由文件,laravel 5.3路由分的很細(xì),有針對(duì)api的,針對(duì)web的,還有針對(duì)命令行的,針對(duì)web的在routes/web.php
中( 路由這樣改個(gè)人覺(jué)得很好,比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>
我們?cè)诨仡^來(lái)說(shuō)下fzaninotto/Faker
包, 默認(rèn)我們生成的測(cè)試數(shù)據(jù)都是英文的,如果你一定要想生成中文的測(cè)試數(shù)據(jù)(其實(shí)沒(méi)啥用),該怎么生成?回到database/factories/ModelFactory.php
在fzaninotto/Faker
源碼中我們可以看見(jiàn)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), ];});
現(xiàn)在生成的姓名就是中文的了,但是該組件對(duì)中文的支持類(lèi)太少,所以你可能會(huì)在寫(xiě)Seeder
的時(shí)候用一部分$faker,用一部分手動(dòng)指定,或者自己寫(xiě)一些數(shù)組,隨機(jī)插入也可以。
本節(jié)到這里結(jié)束。
聯(lián)系客服