在开发过程中,我们经常需要为数据库添加测试数据。Laravel 提供了数据填充(Seeding)功能,允许你使用 PHP 类向数据库中插入测试数据。 结合模型工厂,可以快速生成大量符合规则的数据,极大地提高开发效率。
数据填充是将测试数据插入数据库的过程。Laravel 的 Seeder 类(位于 database/seeders 目录)允许你以编程方式定义要插入的数据。
你可以创建多个 Seeder 文件,分别处理不同表的数据,并通过一个主 Seeder 统一调用。
使用 Artisan 命令创建 Seeder 类:
php artisan make:seeder UserSeeder
php artisan make:seeder PostSeeder
生成的 Seeder 位于 database/seeders 目录,初始内容如下:
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
public function run(): void
{
// 在这里编写插入数据的代码
}
}
在 run 方法中,你可以使用查询构建器或 Eloquent 模型插入数据。
use App\Models\User;
public function run(): void
{
User::create([
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => bcrypt('password'),
]);
}
public function run(): void
{
for ($i = 1; $i <= 10; $i++) {
User::create([
'name' => "User {$i}",
'email' => "user{$i}@example.com",
'password' => bcrypt('password'),
]);
}
}
User::factory()->count(50)->create() 配合模型工厂可以更轻松地生成大量数据,稍后会详细讲解。
php artisan db:seed
这会运行 DatabaseSeeder 类(默认位于 database/seeders/DatabaseSeeder.php),你需要在该类中调用其他 Seeder。
php artisan db:seed --class=UserSeeder
php artisan db:seed --force
模型工厂允许你定义模型的默认数据模板,然后快速生成大量随机数据。Laravel 11 默认集成了 lazy 和 count 方法,并支持 Faker 生成各类假数据。
php artisan make:factory UserFactory --model=User
生成的工厂位于 database/factories 目录,内容类似:
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
protected static ?string $password;
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
];
}
}
fake() 是 Faker 实例的全局辅助函数,可生成姓名、邮箱、地址等各类假数据。
use App\Models\User;
public function run(): void
{
// 生成 10 个用户
User::factory()->count(10)->create();
// 生成一个自定义数据的用户
User::factory()->create([
'name' => 'Admin',
'email' => 'admin@example.com',
]);
}
可以为工厂定义不同状态,以便生成特定场景的数据:
// 在 UserFactory 中添加方法
public function suspended(): static
{
return $this->state(fn (array $attributes) => [
'suspended_at' => now(),
]);
}
// 使用
User::factory()->suspended()->create();
通常我们会在 DatabaseSeeder 中调用所有 Seeder,确保一次运行即可填充所有数据。
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
UserSeeder::class,
PostSeeder::class,
CommentSeeder::class,
]);
}
}
你也可以在 Seeder 内部调用其他 Seeder,实现分模块填充。
假设我们有用户、文章、评论三张表,我们创建一个完整的填充流程。
1. 创建 UserFactory 和 PostFactory
UserFactory 已经默认生成,PostFactory 需要手动创建:
php artisan make:factory PostFactory --model=Post
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory
{
public function definition(): array
{
return [
'title' => fake()->sentence(),
'content' => fake()->paragraphs(5, true),
'user_id' => User::factory(), // 自动关联用户
'is_published' => fake()->boolean(80),
'published_at' => fake()->dateTimeBetween('-1 month', 'now'),
];
}
}
2. 编写 UserSeeder
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
public function run(): void
{
// 创建管理员
User::factory()->create([
'name' => 'Admin',
'email' => 'admin@example.com',
]);
// 创建 20 个普通用户
User::factory()->count(20)->create();
}
}
3. 编写 PostSeeder
namespace Database\Seeders;
use App\Models\Post;
use Illuminate\Database\Seeder;
class PostSeeder extends Seeder
{
public function run(): void
{
// 为每个用户创建 3-10 篇文章
Post::factory()->count(100)->create();
}
}
4. 编写 CommentSeeder
namespace Database\Seeders;
use App\Models\Comment;
use Illuminate\Database\Seeder;
class CommentSeeder extends Seeder
{
public function run(): void
{
// 每篇文章生成 0-20 条评论
Comment::factory()->count(500)->create();
}
}
CommentFactory 中需要定义关联关系:'post_id' => Post::factory()。
5. 在 DatabaseSeeder 中调用
public function run(): void
{
$this->call([
UserSeeder::class,
PostSeeder::class,
CommentSeeder::class,
]);
}
运行 php artisan db:seed,即可填充所有数据。
truncate() 方法先清空表,避免重复数据。在 DatabaseSeeder 中可以调用 User::truncate(),但注意外键约束,可使用 Schema::disableForeignKeyConstraints() 临时关闭。
结合迁移和填充,可以使用一条命令重建数据库并填充数据:
php artisan migrate:refresh --seed
这相当于回滚所有迁移、重新执行迁移、再运行数据填充。
app/Providers/AppServiceProvider 中设置 faker->locale('zh_CN') 可生成中文数据。User::factory() 作为关联字段,会为新用户创建文章,实现嵌套关联。createMany 方法:User::factory()->count(5)->has(Post::factory()->count(3))->create() 可创建用户并同时创建关联文章。createUnverified() 状态:工厂默认支持 unverified 状态(如果已定义),方便生成未验证邮箱的用户。database/seeders/DatabaseSeeder.php 文件开头是否有 namespace Database\Seeders;。如果文件不存在,可以手动创建或使用 composer dump-autoload 刷新自动加载。
run 方法中使用 DB::transaction() 包裹数据插入代码,确保数据一致性。
unique() 方法确保字段唯一,如 fake()->unique()->email()。工厂定义中已默认使用 unique()->safeEmail(),通常不会冲突。
数据填充是 Laravel 开发中不可或缺的工具,通过 Seeder 和工厂,你可以快速生成大量高质量的测试数据,大大提升开发效率。 掌握创建 Seeder、编写插入逻辑、使用模型工厂以及组织填充顺序,将为你的项目带来极大的便利。 下一章我们将学习如何使用 Laravel 的认证系统,快速实现用户注册和登录功能。