When using seeders, the data is often interconnected: we want to seed some data with related records. Is there a "quick" syntax to do it?
If we take a look at Laravel docs, we can find this example:
$user = User::factory() ->has(Post::factory()->count(3)) ->create();
This example assumes that the relationship is User -> hasMany -> Posts.
What this example doesn't cover, is that you can chain this deeper, more than one level. So, let's imagine the scenario of this relationship:
Customer -> hasMany -> Order Order -> hasMany -> Product Product -> hasMany -> Ingredient
And we need to seed the data for Customers, each with X orders, each order with Y products, and each product with Z ingredients.
If we have the Factory classes for those Models ready, we can write this short chain in the CustomerSeeder
or even the DatabaseSeeder
file:
public function run(){ Customer::factory(100) ->has(Order::factory(2)) ->has(Product::factory(3)) ->has(Ingredient::factory(5)) ->create();}
This will create 100 customers, 2 orders for each customer, 3 products for each order, and 5 ingredients for each product.
Looks like a beautiful one-liner, doesn't it?
You can read more about Laravel factories and seeding in the Laravel docs here.
This works really well, but I was wondering, is there a way to randomise the number of orders, products and ingredients being created each time, in order to make the seed data a bit more realistic?
I tried to do
->has(Product::factory(rand(1,3)))
hoping that it would create between 1 and 3 products for each order but acutally it seems as though it only evaluates the random number once so all of the orders have 1, 2 or 3 products depending on the number it chose.I know I can achieve this by using a for loop or even
each()
but then we loose a lot of the beauty of your example.