2

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();
Amit Verma
  • 40,709
  • 21
  • 93
  • 115
Exploit
  • 6,278
  • 19
  • 70
  • 103

6 Answers6

2
    $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
    ];
});

For more info, see the source of this copied quote:

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

-- https://www.dwightwatson.com/posts/building-relations-with-laravel-model-factories

miken32
  • 42,008
  • 16
  • 111
  • 154
  • i get undefined $factory do i need to import a class? not sure which one. same with the factory() function it says undefined. im using laravel 8 – Exploit Apr 03 '21 at 05:03
  • In Laravel 8 , You can use Category::factory() instead of factory() helper methods. And In Category Model add a trait, use HasFactory; – Md. Morshadun Nur Apr 03 '21 at 05:28
2

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

jef
  • 536
  • 1
  • 4
  • 14
1

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

Chin Leung
  • 14,621
  • 3
  • 34
  • 58
1

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()
    );
});
P. K. Tharindu
  • 2,565
  • 3
  • 17
  • 34
0

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.

Exploit
  • 6,278
  • 19
  • 70
  • 103
0
use Illuminate\Support\Str;

public function definition(): array
{
    return [
        'category_id'=>'1',
        'title'=> $this->faker->text(20),
        'slug'  => function ($attr) {
            return Str::slug($attr['title']);
        },
        'content'=> $this->faker->realText($maxNbChars = 200, $indexSize = 2),
        'is_published'=> $this->faker->boolean()
    ];
}
Ricard
  • 1
  • 1