Exploit
Exploit

Reputation: 6386

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();

Upvotes: 2

Views: 5154

Answers (6)

Md. Morshadun Nur
Md. Morshadun Nur

Reputation: 145

    $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

Upvotes: 2

Ricard
Ricard

Reputation: 1

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

Upvotes: 0

P. K. Tharindu
P. K. Tharindu

Reputation: 2730

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()
    );
});

Upvotes: 1

Chin Leung
Chin Leung

Reputation: 14921

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

Upvotes: 1

Exploit
Exploit

Reputation: 6386

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.

Upvotes: 0

jef
jef

Reputation: 542

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

Upvotes: 2

Related Questions