Laravel Many-to-Many: Seed Data with Factories - 3 Ways

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.

avatar

please add fourth one - the one using existing models

avatar

Well, you can use the same create()->each() just inside use whatever logic of existing records you want.

avatar

You can use create()->each() or pass attributes into the create() like this:

create([
'related_id' => $id
])

Of course, this will create ALL entries with the same ID so you have to be careful on how you call this

avatar

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.

👍 1

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1057 lessons, total 42 h 44 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials