我们在前两篇教程中分别介绍了如何连接到数据库,以及如何通过迁移文件定义表结构来创建或修改数据表,接下来,是时候在数据表里添加内容了。在 Laravel 框架中,如果想要快速填充测试数据到数据库,可以借助框架提供的填充器功能,通过填充器,我们可以非常方便地为不同数据表快速填充测试数据。
填充器简介
在应用根目录的 database/seeds
目录下,默认包含一个 DatabaseSeeder.php
文件。这就是 Laravel 自带的一个填充器示例文件,该填充器类提供了一个 run
方法,当我们运行填充命令时,就会调用该方法执行数据库填充。
填充器的运行
Laravel 提供了两种方式来运行填充器:一种是独立的填充命令,另一种是在运行迁移命令时通过指定标识选项在创建数据表时填充。
独立的填充命令如下:
代码语言:javascript复制php artisan db:seed
php artisan db:seed --class=UsersTableSeeder
上述第一个 Artisan 命令会以 DatabaseSeeder
为入口类,调用该类的 run
方法,你可以将所有对其他填充器的调用定义在该方法中,例如:
$this->call(UsersTableSeeder::class);
这样,就可以一次性调用所有填充器啦。
当然,你也可以通过 --class=
选项指定运行某个填充器类的 run
方法。
此外,在某些时候,你可能希望在运行迁移命令的同时填充测试数据,尤其是在初始化一些演示项目的时候。这可以通过不指定值的 --seed
选项来实现:
php artisan migrate --seed
php artisan migrate:refresh --seed
第一条命令用于执行迁移命令时运行填充器类 DatabaseSeeder
填充数据,第二条命令用于回滚所有迁移并重新运行迁移同时填充初始化数据。
编写填充器类
介绍完如何运行填充器,是时候来编写第一个填充器类了。我们可以通过如下 Artisan 命令为 users
表快速创建一个填充器类 UsersTableSeeder
:
php artisan make:seeder UsersTableSeeder
该命令会在 database/seeds
目录下创建一个 UsersTableSeeder
填充器类,初始化代码如下:
<?php
use IlluminateDatabaseSeeder;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
}
}
我们可以将填充逻辑编写到 run
方法里:
public function run()
{
DB::table('users')->insert([
'name' => str_random(10),
'email' => str_random(10).'@gmail.com',
'password' => bcrypt('secret'),
]);
}
这里我们借助了查询构建器(下一篇教程将介绍)来插入数据,指定用户名和邮箱为长度不大于10的随机字符串,邮箱后缀是 @gmail.com
,密码是对 secret
字符串进行加密后的字符串。
这样,我们就编写好了第一个填充器类,接下来,我们可以通过指定填充器类的方式将这条记录插入到数据库:
代码语言:javascript复制php artisan db:seed --class=UsersTableSeeder
你还可以在 DatabaseSeeder
类的 run
方法中运行这个填充器类:
public function run()
{
$this->call(UsersTableSeeder::class);
}
如果有多个填充器类,想要一次性运行,可以将它们都放到这个方法中调用。然后运行如下 Artisan 命令即可:
代码语言:javascript复制php artisan db:seed
这样,就可以在数据表 users
中看到新填充的用户记录了:
当然,我们可以在 UsersTableSeeder
类中定义多条插入语句来一次性插入多条记录。
通过模型工厂填充数据
以上编写填充器类填充数据到数据库虽然已经很方便了,但是每次插入一条记录都要编写一条语句或者手动指定插入数据,如果需要填充的测试数据有成千上万条,那不是要崩溃掉。有没有一种机制可以支持一次定义,多次填充呢?为了解决这个问题,我们需要引入一种模式,一次定义填充规则,在每次具体运行时,通过指定填充次数来决定填充多少条记录。模型工厂的概念应运而生:我们在一个 Eloquent 模型类(后面马上会讲到)上定义一个工厂方法,通过指定规则批量插入填充数据。
你可以想象,有了模型工厂的加持,会为我们日后测试带来多大的便利。现在,我们先抛开测试不谈,赶紧来看下如何在 Laravel 中定义模型工厂。
创建模型工厂
模型工厂位于 database/factories
目录下,Laravel 自带了一个用于填充 User
模型的模型工厂 UserFactory.php
:
<?php
use FakerGenerator 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(AppUser::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
'remember_token' => str_random(10),
];
});
注:在 Laravel 6.0 中,请使用
IlluminateSupportStr::random(10)
替代str_random(10)
调用。
在模型工厂文件中,我们通过 factory->define 方法来定义 User 模型的模型工厂,该方法的第一个参数是模型类,第二个参数是一个匿名函数,在该匿名函数中我们通过 Faker 类库提供的方法来定义字段规则,Faker 类库提供了丰富的字段规则帮助我们生成伪造字段值,这些规则可以在官方文档中查看,这里,我们使用
调用模型工厂
在调用这些模型工厂的时候,需要借助 Laravel 提供的全局辅助函数 factory()
,比如我们在 UsersTableSeeder
的 run
方法中通过模型工厂改写数据填充方法:
public function run()
{
/*DB::table('users')->insert([
'name' => str_random(10),
'email' => str_random(10).'@gmail.com',
'password' => bcrypt('secret'),
]);*/
factory(AppUser::class, 5)->create();
}
我们将之前手动编写填写数据的方式注释起来,替换成新的模型工厂的方式,代码瞬间简洁了很多,由于我们在 UserFactory.php
中全局定义了 User
模型的模型工厂,所以在这里只需调用 factory
方法,传入对应模型类和要填充的记录数即可,最后再调用 create
方法让变更生效。非常方便,也真正实现了一次定义,多处复用,以及在运行时指定填充记录数。
运行填充器的方式还是和填充器类中介绍的一样。比如我们还是通过运行 php artisan db:seed
命令来填充数据到数据库,此时,就可以看到新填充了 5 条记录:
注:本教程都以 Laravel 自带的
users
及对应User
模型类为例进行演示,对于其他数据表和对应模型类,依样画葫芦就好。本系列教程首发在Laravel学院(laravelacademy.org),你可以点击页面左下角阅读原文链接查看最新更新的教程。