theovier
theovier

Reputation: 212

How to seed multiple many-to-many relationships with different pivot data in laravel 8?

I know that I can use the hasAttached method to create many-to-many relationships with pivot data in Laravel 8:

  Meal::factory()
        ->count(3)
        ->hasAttached(Ingredient::factory()->count(3), ['gram' => 100])
        ->create();

Is there any convenient way (other than writing a custom for-loop) to seed the pivot table with random data for each attached entry? I want the 'gram' to be a random number for each of the created relationships. I tried the following but the rand expression just gets evaluated once and fills the pivot table with the same entry for each relationship:

Meal::factory()
        ->count(3)
        ->hasAttached(Ingredient::factory()->count(3), ['gram' => rand(1,100]) //not working
        ->create();

Edit: I basically want to achieve

for ($i = 1; $i <= 3; $i++) {
        $meal = Meal::factory()->create();

        for ($j = 1; $j <= 3; $j++) {
            $ingredient = Ingredient::factory()->create();
            $meal->ingredients()->save($ingredient, ['gram' => rand(5, 250)]);
        }
    }

with Laravel's fluent factory methods.

Upvotes: 7

Views: 2568

Answers (1)

Cl&#233;ment Baconnier
Cl&#233;ment Baconnier

Reputation: 6058

When you call a method like this method(rand(1,100)) the rand is evaluated before the call. It will be the same as doing method(59)

Fortunately, Laravel allow you to use a callback to re-evaluate the parameter on each call,

Meal::factory()
        ->count(3)
        ->hasAttached(Ingredient::factory()->count(3), fn => ['gram' => rand(1,100)])
        ->create();

If you use a PHP version bellow 7.4 you won't be able to use arrow function and you will have to do like this

Meal::factory()
        ->count(3)
        ->hasAttached(Ingredient::factory()->count(3), function () { 
            return ['gram' => rand(1,100)]; 
        })
        ->create();

Upvotes: 14

Related Questions