Laravel — P36: Seeders and Factories (CMP)

Master Data Generation with Laravel Seeders and Factories

Our database has been created, so we’ll work on seeding our tables. I normally like to take care of the database architecture first before I move into the routes/controllers/models, but it’s all preference. If you’re doing TDD (test driven development), it won’t work quite like this. You’ll start with a route, then move to your controller, then your model/migration, etc. We’ll cover TDD later in the series, but for now, let’s look at seeding our tables.

PersonalCarBrand Seeder

Our PersonalCarBrand model contains a name and a slug. Whenever we’re seeding the database, we don’t need to seed accurate information. In other words, it doesn’t matter if we seed the tables with Lamborghini and Ferrari. Each of these are just strings, so we’ll just create some strings and seed them.

First, we need to populate our PersonalCarBrandFactory.

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\PersonalCarBrand>
 */
class PersonalCarBrandFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        return [
            'name' => ucfirst( $word = $this->faker->unique()->word() ),
            'slug' => $word,
        ];
    }
}

The factory just creates a word and then uses that same word for the slug. The unique() method is there to try and generate a unique word for you. Sometimes it won’t work, especially if you’re trying to create large datasets. Also, if you have data already populated in your database, it’ll likely break. That’s why I recommend that you migrate:fresh when you have unique columns in your tables.

The factory can now be added to our PersonalCarBrandSeeder.

<?php

namespace Database\Seeders;

use App\Models\PersonalCarBrand;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class PersonalCarBrandSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        PersonalCarBrand::factory()->count(10)->create();
    }
}

The seeder will generate 10 rows inside of our personal_car_brands table. We just need to add our seeder now to our DatabaseSeeder class and run the seeders.

<?php

namespace Database\Seeders;

// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            UserSeeder::class,
            CarSeeder::class,
            PersonalCarBrandSeeder::class,
        ]);
    }
}
Remember that we already had a couple of seeders here. We’ll stick the PersonalCarBrandSeeder under those two. Run the command:
php artisan db:seed

Sometimes it’s better to rerun all your migrations and seed during that time.

php artisan migrate:fresh --seed

Check your table. It should have some content there.

# php artisan db:seed

   INFO  Seeding database.  

  Database\Seeders\UserSeeder .............................................................................................................. RUNNING  
  Database\Seeders\UserSeeder ....................................................................................................... 103.86 ms DONE  

  Database\Seeders\CarSeeder ............................................................................................................... RUNNING  
  Database\Seeders\CarSeeder ........................................................................................................ 105.51 ms DONE  

  Database\Seeders\PersonalCarBrandSeeder .................................................................................................. RUNNING  
  Database\Seeders\PersonalCarBrandSeeder ............................................................................................ 24.16 ms DONE  


mysql> select * from personal_car_brands;
+----+---------+---------+---------------------+---------------------+
| id | name    | slug    | created_at          | updated_at          |
+----+---------+---------+---------------------+---------------------+
|  1 | Qui     | qui     | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
|  2 | Maiores | maiores | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
|  3 | Quod    | quod    | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
|  4 | Sint    | sint    | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
|  5 | Sit     | sit     | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
|  6 | Ut      | ut      | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
|  7 | Nam     | nam     | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
|  8 | Et      | et      | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
|  9 | Aut     | aut     | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
| 10 | Fugit   | fugit   | 2023-01-20 20:07:43 | 2023-01-20 20:07:43 |
+----+---------+---------+---------------------+---------------------+
10 rows in set (0.00 sec)

PersonalCarModel Seeder

It’s almost unnecessary to illustrate this concept since it’s almost identical. We’ll create the factory, add it to our seeder, add our seeder to the DatabaseSeeder and run the db:seed command.

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\PersonalCarModel>
 */
class PersonalCarModelFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        return [
            'name' => ucfirst( $word = $this->faker->unique()->word() ),
            'slug' => $word,
        ];
    }
}
<?php

namespace Database\Seeders;

use App\Models\PersonalCarModel;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class PersonalCarModelSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        PersonalCarModel::factory()->count(10)->create();
    }
}
<?php

namespace Database\Seeders;

// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            UserSeeder::class,
            CarSeeder::class,
            PersonalCarBrandSeeder::class,
            PersonalCarModelSeeder::class,
        ]);
    }
}
# php artisan migrate:fresh --seed

  Dropping all tables .................................................................................................................... 81ms DONE

   INFO  Preparing database.  

  Creating migration table ............................................................................................................... 17ms DONE

   INFO  Running migrations.  

  2014_10_12_000000_create_users_table ................................................................................................... 27ms DONE
  2014_10_12_100000_create_password_resets_table ......................................................................................... 23ms DONE
  2019_08_19_000000_create_failed_jobs_table ............................................................................................. 25ms DONE
  2019_12_14_000001_create_personal_access_tokens_table .................................................................................. 38ms DONE
  2023_01_12_185409_create_tests_table ................................................................................................... 26ms DONE
  2023_01_12_194511_add_phone_to_tests_table ............................................................................................. 11ms DONE
  2023_01_16_162646_create_cars_table .................................................................................................... 14ms DONE
  2023_01_19_194202_create_personal_car_brands_table ..................................................................................... 34ms DONE
  2023_01_19_194203_create_personal_car_models_table ..................................................................................... 35ms DONE
  2023_01_19_194255_create_personal_cars_table ........................................................................................... 15ms DONE
  2023_01_19_194540_create_images_table .................................................................................................. 14ms DONE
  2023_01_19_194631_create_image_personal_car_table ...................................................................................... 13ms DONE

   INFO  Seeding database.  

  Database\Seeders\UserSeeder .............................................................................................................. RUNNING  
  Database\Seeders\UserSeeder ........................................................................................................ 85.86 ms DONE  

  Database\Seeders\CarSeeder ............................................................................................................... RUNNING  
  Database\Seeders\CarSeeder ........................................................................................................ 121.03 ms DONE  

  Database\Seeders\PersonalCarBrandSeeder .................................................................................................. RUNNING  
  Database\Seeders\PersonalCarBrandSeeder ............................................................................................ 30.66 ms DONE  

  Database\Seeders\PersonalCarModelSeeder .................................................................................................. RUNNING  
  Database\Seeders\PersonalCarModelSeeder ............................................................................................ 28.11 ms DONE
mysql> select * from personal_car_models;
+----+------------+------------+---------------------+---------------------+
| id | name       | slug       | created_at          | updated_at          |
+----+------------+------------+---------------------+---------------------+
|  1 | Qui        | qui        | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
|  2 | Ratione    | ratione    | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
|  3 | Aliquam    | aliquam    | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
|  4 | Ut         | ut         | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
|  5 | Et         | et         | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
|  6 | Sed        | sed        | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
|  7 | Corporis   | corporis   | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
|  8 | Laboriosam | laboriosam | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
|  9 | Quo        | quo        | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
| 10 | Voluptates | voluptates | 2023-01-20 20:20:58 | 2023-01-20 20:20:58 |
+----+------------+------------+---------------------+---------------------+
10 rows in set (0.00 sec)

PersonalCar Seeder

The PersonalCarFactory is slightly different since it relies on data from the other tables. We could just assign a static id, and many developer do, but we’ll utilize the eloquent model to get us a random row.

<?php

namespace Database\Factories;

use App\Models\PersonalCarBrand;
use App\Models\PersonalCarModel;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\PersonalCar>
 */
class PersonalCarFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        return [
            'year' => $this->faker->year(),
            'personal_car_brand_id' => PersonalCarBrand::inRandomOrder()->first()->id,
            'personal_car_model_id' => PersonalCarModel::inRandomOrder()->first()->id,
            'is_manual' => $this->faker->boolean,
            'exterior_color' => $this->faker->word(),
            'purchase_amount' => $this->faker->randomNumber(8),
            'current_value' => $this->faker->randomNumber(9),
            'sales_amount' => 0,
            'date_purchased' => $this->faker->date(),
        ];
    }
}

The year is pretty straightforward. The two foreign id’s for the brand and the model, utilize each model. First, we sort the table in random order (inRandomOrder), return the first() instance and then select the id. This will give us a random brand and model id. All of the other fields are straightforward.

You might have noticed that in the previous article we also had date_sold. Since it contains a default value of null, it’s not required for us to define it inside of our factory. We can simply rely on MySQL to do it for us.

Everything else is the same as before. Add the factory to the seeder, the seeder to the DatabaseSeeder and run your seed command.

<?php

namespace Database\Seeders;

use App\Models\PersonalCar;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class PersonalCarSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        PersonalCar::factory()->count(10)->create();
    }
}
<?php

namespace Database\Seeders;

// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            UserSeeder::class,
            CarSeeder::class,
            PersonalCarBrandSeeder::class,
            PersonalCarModelSeeder::class,
            PersonalCarSeeder::class,
        ]);
    }
}
# php artisan migrate:fresh --seed

  Dropping all tables .................................................................................................................... 83ms DONE

   INFO  Preparing database.  

  Creating migration table ............................................................................................................... 17ms DONE

   INFO  Running migrations.  

  2014_10_12_000000_create_users_table ................................................................................................... 28ms DONE
  2014_10_12_100000_create_password_resets_table ......................................................................................... 24ms DONE
  2019_08_19_000000_create_failed_jobs_table ............................................................................................. 25ms DONE
  2019_12_14_000001_create_personal_access_tokens_table .................................................................................. 36ms DONE
  2023_01_12_185409_create_tests_table ................................................................................................... 25ms DONE
  2023_01_12_194511_add_phone_to_tests_table ............................................................................................. 11ms DONE
  2023_01_16_162646_create_cars_table .................................................................................................... 14ms DONE
  2023_01_19_194202_create_personal_car_brands_table ..................................................................................... 35ms DONE
  2023_01_19_194203_create_personal_car_models_table ..................................................................................... 31ms DONE
  2023_01_19_194255_create_personal_cars_table ........................................................................................... 13ms DONE
  2023_01_19_194540_create_images_table .................................................................................................. 14ms DONE
  2023_01_19_194631_create_image_personal_car_table ...................................................................................... 12ms DONE

   INFO  Seeding database.  

  Database\Seeders\UserSeeder .............................................................................................................. RUNNING  
  Database\Seeders\UserSeeder ........................................................................................................ 94.26 ms DONE  

  Database\Seeders\CarSeeder ............................................................................................................... RUNNING  
  Database\Seeders\CarSeeder ........................................................................................................ 117.66 ms DONE  

  Database\Seeders\PersonalCarBrandSeeder .................................................................................................. RUNNING  
  Database\Seeders\PersonalCarBrandSeeder ............................................................................................ 23.60 ms DONE  

  Database\Seeders\PersonalCarModelSeeder .................................................................................................. RUNNING  
  Database\Seeders\PersonalCarModelSeeder ............................................................................................ 24.50 ms DONE  

  Database\Seeders\PersonalCarSeeder ....................................................................................................... RUNNING  
  Database\Seeders\PersonalCarSeeder ................................................................................................. 43.80 ms DONE  

# 
mysql> select * from personal_cars;
+----+------+-----------------------+-----------------------+-----------+----------------+-----------------+---------------+--------------+----------------+-----------+---------------------+---------------------+
| id | year | personal_car_brand_id | personal_car_model_id | is_manual | exterior_color | purchase_amount | current_value | sales_amount | date_purchased | date_sold | created_at          | updated_at          |
+----+------+-----------------------+-----------------------+-----------+----------------+-----------------+---------------+--------------+----------------+-----------+---------------------+---------------------+
|  1 | 2022 |                     6 |                     6 |         1 | itaque         |        21846038 |     635120796 |            0 | 2014-01-18     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
|  2 | 1999 |                     9 |                     2 |         0 | sequi          |        44511427 |     697656828 |            0 | 1995-04-23     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
|  3 | 1991 |                     9 |                     2 |         0 | incidunt       |        23012254 |     882379214 |            0 | 1987-09-07     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
|  4 | 2018 |                     3 |                     1 |         0 | mollitia       |        47028382 |     285870699 |            0 | 1985-05-25     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
|  5 | 1991 |                     7 |                    10 |         0 | tempora        |        28457362 |     720832497 |            0 | 1984-05-10     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
|  6 | 2014 |                     8 |                     4 |         1 | id             |        64666626 |     707879572 |            0 | 1980-12-25     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
|  7 | 1986 |                     4 |                     9 |         0 | qui            |        36442230 |     410003910 |            0 | 1977-07-06     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
|  8 | 1974 |                     7 |                     4 |         1 | tenetur        |         2236172 |     779288418 |            0 | 1979-07-15     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
|  9 | 1971 |                     8 |                     6 |         0 | voluptate      |        75415740 |     575873464 |            0 | 1997-10-14     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
| 10 | 1992 |                    10 |                     4 |         0 | mollitia       |        26363032 |     806291570 |            0 | 1987-07-11     | NULL      | 2023-01-20 20:37:11 | 2023-01-20 20:37:11 |
+----+------+-----------------------+-----------------------+-----------+----------------+-----------------+---------------+--------------+----------------+-----------+---------------------+---------------------+
10 rows in set (0.00 sec)

mysql> 
And that’s it. We’re ready to prep our models next. We need to setup some relationships inside of each model and we can use tinker to verify that these relationships work. We’ll do that in the next article.

Laravel Series

Continue your Laravel Learning.

Laravel — P35: Database Setup (CMP)

Setting the Stage: Database Configuration for the Car Management Project

Laravel – P35: Database Setup (CMP)

Prepare your CMP with Laravel: A step-by-step guide to setting up your database. Ensure a solid foundation for your vehicle management app.

Laravel — P36: Seeders and Factories (CMP)

Master Data Generation with Laravel Seeders and Factories

Laravel — P36: Seeders and Factories (CMP)

Learn how to efficiently use Laravel seeders and factories for data generation in your projects. Boost productivity and streamline your workflow.

Laravel — P37: Models $fillable, belongsTo and hasMany (CMP)

Mastering Models in Laravel: $fillable, belongsTo, and hasMany

Laravel – P37: CMP – Models $Fillable, Belongsto and  Hasmany

Explore Laravel models with a focus on $fillable, belongsTo, and hasMany. Understand how to efficiently manage relationships and data handling in your projects.

Leave a Reply