Skip to main content
Tutorial Free

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

August 06, 2023
3 min read

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.

Enjoyed This Tutorial?

Get access to all premium tutorials, video and text courses, and exclusive Laravel resources. Join our community of 10,000+ developers.

Comments & Discussion

D
dascorp ✓ Link copied!

please add fourth one - the one using existing models

PK
Povilas Korop ✓ Link copied!

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

M
Modestas ✓ Link copied!

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

D
dascorp ✓ Link copied!

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.

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.