Insert mass database records using model factories in Laravel

Amit Merchant · August 17, 2020 ·

One of the many ways using which you can insert records (or seed your database) is by using the seeder classes which extend a base class called Illuminate\Database\Seeder in Laravel.

For instance, if you want a seeder for say books table, you can generate it using the following command like so.

$ php artisan make:seeder BookSeeder

This will generate the seeder class under the database/seeds directory which looks like the following.

<?php

use Illuminate\Database\Seeder;

class BookSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}

Now, the class only contains a method called run and this is where you can write queries to insert records like so.

public function run()
{
    DB::table('books')->insert([
            'name' => Str::random(10),
            'author' => Str::random(10),
            'type' => Str::random(10),
        ]);
}

Now, whenever you run the seeders, it will add a record in the books table with random values as shown above. This alright but what if you want more records for your testing purposes? You certainly won’t repeat multiple insert queries inside of the run, right?

And this is where model factories come into the picture.

Model Factories

In a nutshell, model factories are nothing but PHP files (not classes) using which Laravel allows you to set a default set of attributes for each of your Eloquent models.

A factory can be generated by using make:factory Artisan command. So, if we want to generate a factory for our Book model, we can generate it like so.

$ php artisan make:factory BookFactory

This will generate a PHP file called BookFactory.php under database/factories directory and it would look like so.

<?php

use App\Book;
use Illuminate\Support\Str;
use Faker\Generator as Faker;

$factory->define(Book::class, function (Faker $faker) {
    $type = ['fiction', 'nonfiction'];

    return [
        'name' => $faker->word,
        'author' => $faker->name,
        'type' => $type[rand(0, (count($type)-1))]
    ];
});

As you can see, Laravel gives us Faker PHP library at our disposal in the factory definition which is a Closure. Here, we can set the default values for attributes by returning an attributes array using the Faker library. Once done, we can now use this factory as a base to our BookSeeder which will generate database records using factory definition.

For instance, if you want to generate, say 20 records based on this factory, you can use it in the BookSeeder like so.

public function run()
{
    factory(App\Book::class, 20)->create()->each(function ($book) {
        $book->save(factory(App\Book::class)->make());
    });
}

This will generate 20 records for the books table without cluttering your code too much and is also easy to maintain.

Of course, you can also attach a relationship over here. So, if we want to attach a sales relationship, you can do it like so.

$book->sales()->save(factory(App\Book::class)->make());

Hi there! I'm Amit. I write articles about all things web development. If you like what I write and want me to continue doing the same, I would like you buy me some coffees. I'd highly appreciate that. Cheers!