laravel 使用 seeder 类完成数据填充。 所有的 seed 类都存放在 database/seeds 目录下。你可以任意为 seed 类命名,但是更应该遵守类似 UsersTableSeeder 的命名规范。Laravel 默认定义的一个 DatabaseSeeder 类。可以在这个类中使用 call 方法来运行其它的 seed 类从而控制数据填充的顺序。

有两种运行数据填充

  1. 和数据迁移一起
  1. # 在任何迁移后加上 --seed 即可
  2. php artisan migrate --seed
  3. php artisan migrate:refresh --seed
  1. 单独运行
# 默认运行 DatabaseSeeder 的 run() 方法
php artisan db:seed
php artisan db:seed --class=VotesTableSeeder

创建 Seeder

php artisan make:seeder ContactsTableSeeder

将在 database/seeds 目录生成一个文件 ContactsTableSeeder.php 文件

在编辑它之前,要先在 DatabaseSeeder.php 调用它

// database/seeds/DatabaseSeeder.php
...
public function run()
{
    $this->call(ContactsTableSeeder::class);
}

现在,我们编辑它,插入一条数据如下

<?php
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;

class ContactsTableSeeder extends Seeder
{
    public function run()
    {
        DB::table('contacts')->insert([
            'name' => 'Lupita Smith',
            'email' => 'lupita@gmail.com',
        ]);
    }
}

但是你会发现,实际开发中我们总希望插入很多随机生成的数据,以供测试,这就要使用到模型工厂。

模型工厂

模型工厂实际是定义了一系列生成测试数据的规则,你可以向下面那样定义一个工厂。

// 使用 Eloquent 类 
$factory->define(User::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
    ];
});

// or 使用表名
$factory->define('users', function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
    ];
});

创建一个模型工厂

php artisan make:factory ContactFactory

将会在 database/factories 目录中,生成一个 ContactFactory.php 的文件。

// 参数 1 : 模型工厂的名字, 参数 2 一个闭包用于返回模型生成规则  
$factory->define(Contact::class, function (Faker\Generator $faker) {
    return [
        'name' => 'Lupita Smith',
        'email' => 'lupita@gmail.com',
    ];
});

现在我们可以使用 factory() 的全局函数在 seeder 或者 测试 中插入记录了。

// Create one
$contact = factory(Contact::class)->create();

// Create many
factory(Contact::class, 20)->create();

但是,你插入20条数据,数据都是一样的。用处不大,所以我们现在使用 闭包中的 Faker 实例,完成更多效果。

$factory->define(Contact::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->email,
    ];
});

现在你每插入一条数据就随机生成一条,且邮箱唯一。

使用模型工厂

模型工厂主要被用于 测试 和 seeder

seeder 中的使用

// database/seeds/ContactsSeeder.php
public function run()
{
    // 创建 50 条数据
    factory(Contact::class, 50)->create();
}
// 高级的应用
factory(User::class, 20)->create()->each(function ($u) use ($post) {
    $post->comments()->save(factory(Comment::class)->make([
        'user_id' => $u->id,
    ]));
});

make() vs create()

create() 创建数据 make() 相当于创建了但是没保存 $user = new User(); $user->name='111'; 没有执行 $user->save();

创建并覆盖特别字段

factory(Contact::class, 50)->create([
    'title'=>'test title';
]);

表存在关联怎么写模型工厂

// 
$factory->define(Contact::class, function (Faker\Generator $faker){
    return [
        'name' => 'XXX',
        'email' => '29@aa.com'
        'company_id' => function(){
            return factory(App\Company::class)->create()->id;
        }
    ];
})

一个属性的值是另一个其他属性

$factory->define(Contact::class, function(Faker\Generator $faker){
    return [
        'name' => 'XXX',
        'email' => 'XXX@aa.com',
        'company_id' => function(){
            return factory(App\Company::class)->create()->id;
        }
        'company_size' => function($contact) { // 公司规模 先查找公司 再获取 zize
            return App\Company::find($contact['company_id'])->size;
        }
    ];
})

状态值的处理 state()

// factory 中定义
$factory->state(Contact::class, 'normal', [
    'vip' => false,
]);
$factory->state(Contact::class, 'vip', function (Faker\Generator $faker) {
    return [
        'vip' => true,
        'vip_score' => mt_rand(1, 100),
    ];
});


// seed 中调用
factory(\App\Contact::class, 3)->state('vip')->create();
factory(\App\Contact::class, 30)->state('normal')->create();