简体   繁体   中英

Laravel Faker Factory Relationship

I have two factories one for categories and another for products. When I run the factory I want to create x number of products for each category generated. how would I write the code to product this?

the definition for the categories is written as this:

return [
            'name' => $this->faker->word,
            'slug' => Str::slug($this->faker->unique()->word, '-'),
        ];

and the definition for the product is written as such:

return [
                'category_id' => 1, //instead of 1 the category id used i want to be random
                'name' => $this->faker->word,
                'slug' => Str::slug($this->faker->unique()->word, '-'),
                'description' => $this->faker->paragraph,
                'price' => $this->faker->randomFloat(2, 0, 10000),
                'is_visible' => 1,
                'is_featured' => 1
            ];

as you can see I hardcoded the category_id , I wasnt too sure how to have it automatically generate and create a product per category that exists. I have the factory for the category written as this, to create 10 items

Category::factory()
                ->count(10)
                ->create();

I tried this for trial and error thinking it would work but I get an error that category_id cannot be null .

Product::factory()
                ->has(Category::factory()->count(2))
                ->count(20)
                ->create();
    $factory->define(Product::class, function (Faker $faker) {
    return [
        'category_id' => factory(Category::class), //instead of 1 the category id used i want to be random
        'name' => $this->faker->word,
        'slug' => Str::slug($this->faker->unique()->word, '-'),
        'description' => $this->faker->paragraph,
        'price' => $this->faker->randomFloat(2, 0, 10000),
        'is_visible' => 1,
        'is_featured' => 1
    ];
});

By setting the attribute to an instance of factory() Laravel will lazily create that model as well and automatically associate it

I am using kind of different syntax, but I think it will work / you can change it

In your Category.php model

public function products() {
    return $this->hasMany(Product::class);
}

In seeder

factory(App\Category::class, 10)->create()->each(function($c) {
    $c->products()->save(factory(App\Product::class)->make());
}); // each Category will have 1 product

Laravel Database Testing Relationships

You simply need to pass a CategoryFactory to category_id .

return [
    'category_id' => Category::factory(),
    // ...
];

You can read more about factories here: https://laravel.com/docs/8.x/database-testing#defining-relationships-within-factories

If you want to create multiple products per each created category, you can do something like this:

// CategoryProductSeeder
$categories = Category::factory(50)->create();


$categories->each(function ($category) {
    $categories->products()->saveMany(
        Product::factory(10)->make()
    );
});

this is what worked for me since I'm using laravel 8.

product definition:

return [
            'category_id' => Category::factory(),
            'name' => $this->faker->word,
            'slug' => Str::slug($this->faker->unique()->word, '-'),
            'description' => $this->faker->paragraph,
            'price' => $this->faker->randomFloat(2, 0, 1000),
            'is_visible' => 1,
            'is_featured' => 1
        ];

seeder:

Product::factory()
                ->has(Category::factory())->count(50)
                ->create();

created 50 categories and 50 products. 1 category assigned to each product.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM