6

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.

theovier
  • 184
  • 11
  • I don't have anything to try it right now, but does this works? `->hasAttached(Ingredient::factory()->count(3), fn() => ['gram' => rand(1,100])` – Clément Baconnier Oct 11 '20 at 13:41
  • 1
    @ClémentBaconnier it does! Thank you very much. You might want to post it as an answer and I'll accept it. – theovier Oct 11 '20 at 13:45

1 Answers1

12

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();
Clément Baconnier
  • 5,718
  • 5
  • 29
  • 55