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
You can use Markdown
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
avatar
You can use Markdown
avatar
You can use Markdown

Recent New Courses