Laravel - Factory & Seeding on a Pivot Table with Custom Fields/Columns

Tuan Burah
9 min readSep 7, 2021

How to enable factory faker & seed it on a many-to-many relationship with custom columns?

I’ve spent 12 hours finding for a solution to this problem, as this was my final year project, it was necessary to show the test data using Laravel Factory in my documentation so I couldn’t give up. After playing around with the code and it’s logics for so long I finally came to understand the ergonomics of the Laravel OOP 😁 So I will explain it all from the beginning, from the point of creating a Many-to-Many relationship. You can skip to Part 09 if you want to get to the point of seeding the data into the pivot table.

Supported for Laravel v5.6 and above

Part Zero : The Beginning

You have to understand that there are two ways to create a relationship in Laravel,

  • the raw method:
    a very complex method of coding with only Object Oriented (OO) PHP, good for professionals, not advisable to use since the main point of using the Laravel framework is to use helpers and make things smoother.
  • use of Laravel helpers:
    this is where we have to learn and use the Laravel helpers and how they work apart from knowing the basics of OO PHP.

Part 01: Models — Do we need to make a separate pivot Model?

NO! Creating a separate model will make the entire application more complex, meaning you’ll be going off the grid from Laravel’s perfectly built OO system (or helpers).

In this case, we have to create Two models but Three tables. I will demonstrate the two models as User & Course where,

One user may have one or more courses and One course may have zero or more users.

Two of the three tables will be named as User & Course like the models but the third table will be the called the Pivot table, which is the relationship table between the two models.

Part 02: Create a Model

Note: you don’t necessarily need to create a User model & table because it is already created by default in Laravel if you have loaded the Laravel Authentication UI
— read the Laravel documentation

You can create a model by the following code in the terminal.

php artisan make:model User --migrationphp artisan make:model Course--migration

Make sure you use the --migration flag to automatically generate a migration table at the same time.

Part 03: State the Relationships

Read the following code in the image and made similar adjustments to your models.

Custom fields or columns in your pivot table will be mentioned in BOTH models as an array with the object name ->withPivot([...])

To enable timestamps in the pivot table you have to mention withTimeStamps() in BOTH the models.

Course Model

The USER model will have some other details compared to the COURSE model and that is due to the authentication functions. Focus on the code in the public function courses(){...} only and ignore the rest.

User Model

See carefully how the two models have been related, they are not the same, but different. You have to place the foreign key and primary key of the respective model in the correct place of the relationship or else the relationship will not work.

Part 04: User & Course Tables

There is nothing to change in the User and Course tables that may relate to the Many-to-Many relationship. You can leave it as it is.

User Table
Course Table

Part 05: Creating a Pivot Table

What is a Pivot table?
This is the relationship table refenced as “pivot table” in Laravel. You can create a pivot table by using the following code in the terminal.

php artisan make:migration create_course_user_table --create --table=course_user

You have to make sure the name of the table should follow the alphabetical order of the first letter of both names and must be named as course_user and not user_course. You can use a custom name as the table name, if you’d like, but the table name will need to be defined in the relationship also, stated in the respective models, but in this case I have avoided the unnecessary struggle. If the alphabetical order is not made correctly the relationship will not work as we are using Laravel helpers to generate a relationship.

Pivot Table

Take note on how the foreign keys are been stated carefully. You also can embed the cascading roles such as ->onDelete("cascade"); at the end of the foreign key statement to delete the record if the user or course records has been deleted.

We have now completed establishing the relationships and now we can move onto seeding data into the pivot tables.

Part 06: About Laravel Factory & Seeding

To create fake data and seed it into a migration, we have to follow 03 simple steps.

  • Make a Factory :
    Here we will define the fake data into the defined-respective columns including the type of data we require. You may can refer to the Laravel Faker generator GitHub repository documentation for help on define different types of data, link attached below.

GitHub — fzaninotto/Faker: Faker is a PHP library that generates fake data for you

  • Make a Seeder :
    Here we will need to define how the fake data, defined in the Factory, will populate a particular table or migration. Seeder files are made for cases like these; a many-to-many relationships, a one-to-many relationships and even defines the number of data to be filled in the table. You can create advance logics for your fake data in this file.
  • Run the seeder :
    mention the seeder files we created in the DatabaseSeeder.php file since all seeder files are child components of the Laravel’s OOP and needs to be run on command.

Part 07: Make Factory for Course & User

The factory the the point where we can create fake data using Laravel’s Faker to create fake data. But the catch is every factory file must have a model related to it. Therefore we cannot create a factory file for a Pivot table but we can do it for the User & Course tables.

php artisan make:factory AcademicFactory --model=Coursephp artisan make:factory UserFactory --model=User
Course Factory
User Factory

Take note on how the fake data are been created carefully and replicate it to your code following the changes respectively.

Part 08: Make Seeders for Course & User

I will show you how to create fake data and a seeder for the Pivot table in the next part bcz before that we have to make the seeder for the current two tables.

php artisan make:seeder UsersTableSeederphp artisan make:seeder AcademicsTableSeeder
Users Table Seeder
Course Table Seeder

The course table seeder can be populated similar to the User table seeder, but as you can see in the image, I have used an alternative method and that is solely because I have linked the Course table to another table called “Lecturer” and defined that as a one-to-many relationship. Meaning, for every record in the Lecturer table, a course will be created with an id of the Lecturer table as a foreign-key. You can now realize why I stated the foreign-key in the Course migration in Part 04.

In this case you don’t have to worry about the changes Ihave done in the Course table seeder because that does not affect the many-to-many relationship between the USER and COURSE tables.

This Part 08 is just to populate the USER and COURSE tables a fake data.

Part 09: Pivot Table Seeding and Faker

Now we have come to the point of the question, the problem and the main topic,

How to enable factory faker & seed it on a many-to-many relationship with custom columns?

We have already defined the process for creating custom columns in Part 03 and Part 04, so make sure you have done those steps correctly in order to follow the below process.

To do this, as I have mentioned in Part 08, you do not need a separate Factory file or even a Seeder file. All you need is one of the two seeder files created to make the relationship, i.e. in this case the UsersTableSeeder or AcademicsTableSeeder as shown in Part 08

I have used the AcademicsTableSeeder to populate the pivot table, nothing specifically in this file that can affect the seeding, you can use either of them if you follow the right code.

NOTE!
You have to call the Faker helper function from Laravel on the top respective seeding file to proceed in this method since we will be using the Factory classes to generate the fake data.

use Faker\Factory as Faker;

Where to write the seeding for the pivot table

As you can see in the image we need to define the following code within the run() class of the respective seeder file. Now you know where to write the pivot seeders.

Describing how the code works.
Line 22 — First we read every record in the Course table using a foreach() function.
Line 23 — Then we assign a $faker variable with the Faker::create() function so we don’t have to repeat that long line.
Line 24 — Next we will read a random number records (i.e. One to Three in this case) from the Users table and pluck the id of that record and assign that to the $users variable.
Line 25 — This line is the Jackpot you’ve been waiting for so long so take rest to understand it. I will explain it below in depth.

Seeding the Pivot Table — same code as previous image

In this line (i.e. Line 25) we will call the particular Course record (i.e. $coursefrom the foreach expression) and reach for the relationship of the Course model (i.e. defined as users() in Part 03) and then attach the plucked id (i.e. the variable $users)into the relationship thus creating a link between the two tables Users & Courses.

Now you may be wondering that it is not ethically correct considering the composite primary keys, and I have an answer to that,

“SHAZAAM! Laravel Eloquent does not support composite primary keys!”

Yes! that’s right, there is no helper in Laravel that can work around the composite primary keys thus leaving us with only one way to solve that problem too,

“Use some PHP logics to detect and avoid repeated data following integrity constraints.”

Since what we are doing here is only populating data into a Pivot table I did not waste my time trying to write a logic to a database seeder, but I made sure to put some effort figuring it out to use it in the controller when the real data is loaded into the database. I have stated my solution in a Stack Overflow forum, you may find better solutions there replied by other professionals. The algorithm I wrote, is so far the best solution and it works fine, so you may copy it right away.

php — How to make composite/multiple primary key in Laravel >= 5.6? — Stack Overflow

Now back again to Line 25!

I explained to you up to the point of the variable$users,so next you have to define the fake data to the custom columns/fields similar to the process use in a Factory file as an array. If you have defined the custom columns/fields in the models correctly then this will work smoothly.

Voila!

Now all you need to do is run the migration and test how it works.

php artisan migrate:fresh --seedorphp artisan db:seed --class=AcademicsTableSeeder

If you have any questions regarding the process please do comment below or reach me on my Stack Overflow account. Note that this method is functional on Laravel versions 5.6, 5.7, 5.8 up to 6.2. There may be small changes needed to be made for other versions due to the complexity or deprecated libraries of Laravel helpers.

References

--

--

Tuan Burah

M.Sc. in IT (reading) | Pg.D. in IT | Student Member of British Computer Society — Royal Charter | Member of LivePhysics Science Community