When you have a belongsToMany relationship, it's tricky to add the records in your Seeders/Factories. In this tutorial, I will show you three ways.
Setup: Model Factories
For this example, we will have three things:
-
User
model -
Task
model - Many-to-Many between them
app/Models/User.php
public function tasks(): BelongsToMany{ return $this->belongsToMany(Task::class);}
First, we will need a User factory and a Task factory, without any relationships for now.
User Factory
public function definition(): array{ return [ 'name' => fake()->name(), 'email' => fake()->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10), ];}
Task Factory
public function definition(){ return [ 'name' => fake()->name(), ];}
Now, how to seed Users and assign a Task to each user?
I will show you three options, from the worst to the best one, in my opinion.
Option 1: afterCreating()
You can modify the User Factory and create Tasks every time after the User is created:
User Factory
// ...public function configure(){ return $this->afterCreating(function (User $user) { // Will create 3 tasks for each new user Task::factory()->count(3)->create([ 'user_id' => $user->id, ]); });}
And then, tasks will be created automatically when simply creating a user:
User::factory()->create();
But the problem is that it will always create tasks. You will not be able to create a user without tasks. This is not ideal.
Option 2: create()->each()
The second way is to edit Seeders: call ->each()
after creating User and create tasks manually:
User Seeder
$users = User::factory() ->count(10) ->create() ->each(function(User $user) { Task::factory() ->count(3) ->create([ 'user_id' => $user->id, ]); });
This solves our problem of creating users without tasks. But the code still looks too long. There's a better way.
Option 3: has()
Once again, Laravel has a solution for us. We can use the has()
method after calling Factories to tell them to create a relationship. Let's see how this works.
User Seeder
User::factory() // This tells the factory to create a relationship ->has(Task::factory()) ->count(10) ->create();
As you can see, this is very simple, and it gives us the result we need:
If you need more tasks created per user, you can pass the number to the has()
method:
User::factory() // Adding ->count(5) will create 5 tasks per user ->has(Task::factory()->count(5)) ->count(10) ->create();
This will give us the following result of multiple tasks per user:
That's it! You can read more about this in the official documentation.
please add fourth one - the one using existing models
Well, you can use the same
create()->each()
just inside use whatever logic of existing records you want.You can use
create()->each()
or pass attributes into thecreate()
like this:Of course, this will create ALL entries with the same ID so you have to be careful on how you call this
My comment was more of a feedback than a question. I believe it would help newcomers to see practical examples of this use case. Anyway, your response will guide them in a good direction.