PHP项目Laravel工厂模式生成数据

wen PHP项目 4

本文目录导读:

PHP项目Laravel工厂模式生成数据

  1. 基础使用
  2. 创建自定义工厂
  3. 关联模型工厂
  4. 高级用法
  5. 测试中使用
  6. Seeder中使用
  7. 性能优化技巧
  8. 常用数据类型生成
  9. 自定义数据生成器
  10. 注意事项

在Laravel中,工厂模式(Factory Pattern)是用于生成测试数据的强大工具,以下是完整的实现方案:

基础使用

生成单个模型数据

use App\Models\User;
// 创建单条数据(不保存)
$user = User::factory()->make();
// 创建单条数据(保存到数据库)
$user = User::factory()->create();
// 创建多条数据
$users = User::factory()->count(10)->create();

创建自定义工厂

生成工厂文件

php artisan make:factory UserFactory --model=User

定义工厂结构

<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
    protected $model = User::class;
    public function definition()
    {
        return [
            'name' => fake()->name(),
            'email' => fake()->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => bcrypt('password'),
            'remember_token' => Str::random(10),
        ];
    }
    // 自定义状态
    public function admin()
    {
        return $this->state(function (array $attributes) {
            return [
                'role' => 'admin',
                'is_active' => true,
            ];
        });
    }
    public function unverified()
    {
        return $this->state(fn (array $attributes) => [
            'email_verified_at' => null,
        ]);
    }
}

关联模型工厂

一对多关系

// PostFactory.php
public function definition()
{
    return [
        'user_id' => User::factory(),
        'title' => fake()->sentence(),
        'content' => fake()->paragraph(),
    ];
}

多对多关系

// 创建带有标签的文章
$post = Post::factory()
    ->has(Tag::factory()->count(3))
    ->create();
// 或者使用关系
public function tags()
{
    return $this->belongsToMany(Tag::class);
}

高级用法

动态属性

// 使用回调动态生成数据
User::factory()->create([
    'name' => '特定名称',
    'email' => function () {
        return fake()->unique()->safeEmail();
    }
]);

序列化状态

// 交替使用不同的状态
$users = User::factory()
    ->count(10)
    ->sequence(
        ['role' => 'admin'],
        ['role' => 'editor'],
        ['role' => 'user'],
    )
    ->create();

批量创建带关系的数据

// 创建用户并关联文章
User::factory()
    ->count(5)
    ->has(Post::factory()->count(3))
    ->create();
// 更复杂的关系
$user = User::factory()
    ->has(Profile::factory())
    ->hasPosts(3)
    ->hasComments(5)
    ->create();

测试中使用

public function test_user_can_create_post()
{
    // 创建测试用户
    $user = User::factory()->admin()->create();
    // 创建文章
    $post = Post::factory()->create([
        'user_id' => $user->id
    ]);
    // 验证
    $this->assertDatabaseHas('posts', [
        'id' => $post->id,
        'user_id' => $user->id
    ]);
}

Seeder中使用

// DatabaseSeeder.php
public function run()
{
    // 创建10个用户
    User::factory()->count(10)->create();
    // 创建带有特定关系的复合数据
    User::factory()
        ->count(5)
        ->create()
        ->each(function ($user) {
            Post::factory()
                ->count(fake()->numberBetween(1, 5))
                ->create(['user_id' => $user->id]);
        });
}

性能优化技巧

// 大量数据创建时使用chunk
collect(range(1, 1000))->chunk(100)->each(function ($chunk) {
    User::factory()->count($chunk->count())->create();
});
// 使用数据库事务提高性能
DB::transaction(function () {
    User::factory()->count(1000)->create();
});

常用数据类型生成

class ProductFactory extends Factory
{
    public function definition()
    {
        return [
            'sku' => fake()->unique()->ean13(),
            'name' => fake()->words(3, true),
            'price' => fake()->randomFloat(2, 100, 1000),
            'quantity' => fake()->numberBetween(0, 100),
            'description' => fake()->paragraphs(2, true),
            'manufacturer' => fake()->company(),
            'date_available' => fake()->dateTimeThisYear(),
            'status' => fake()->randomElement(['active', 'inactive']),
        ];
    }
}

自定义数据生成器

// 创建自定义数据提供器
use Faker\Provider\Base as FakerProvider;
class CustomProvider extends FakerProvider
{
    public function customId()
    {
        return 'CUS-' . $this->generator->unique()->numberBetween(100000, 999999);
    }
}
// 在工厂中使用
public function definition()
{
    $this->faker->addProvider(new CustomProvider($this->faker));
    return [
        'custom_id' => $this->faker->customId(),
    ];
}

注意事项

  1. 唯一性约束:使用unique()方法确保数据不重复
  2. 性能考虑:大批量生成数据时注意内存使用
  3. 优先级:显式传入的数据优先于工厂定义
  4. 测试隔离:测试中使用RefreshDatabase trait
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProductTest extends TestCase
{
    use RefreshDatabase;
    public function test_create_product()
    {
        $product = Product::factory()->create();
        $this->assertDatabaseHas('products', ['id' => $product->id]);
    }
}

工厂模式在Laravel中不仅用于测试,也是开发阶段填充数据的最佳实践,可以大幅提高开发效率。

抱歉,评论功能暂时关闭!