Database seeding is a convenient function, but it is designed to run once, in the beginning of the project. What if later you want to add some new seeder and unable to run db:seed or migrate:fresh because of current data is already important?

As example, we want to seed two Role entries, with database/seeds/RolesTableSeeder.php:

use Illuminate\Database\Seeder;

class RoleSeed extends Seeder
{
    public function run()
    {
        $items = [            
            ['id' => 1, 'title' => 'Administrator'],
            ['id' => 2, 'title' => 'Simple user'],
        ];

        foreach ($items as $item) {
            Role::create($item);
        }
    }
}

You also seed and specify IDs as 1 and 2, because they are important to assign users to roles later in the app.

Now, what if you want to change your Role name later in the project? Here are the options:

  • Create a migration file for that with Role::find(1)->update(); statement;
  • Create a specific seed file and run php artisan db:seed –class=NewRoleSeeder
  • Modify existing seeder and re-run php artisan db:seed for the whole app.

The last option seems impossible because running the seed file above will cause an error that entry with ID 1 already exists.

Now, here’s the trick, whenever creating a seed file: use Eloquent updateOrCreate() instead of create() method.

Long version to check if every record exists:

foreach ($items as $item) {
  $role = Role::find($item['id']);
  if ($role) {
    $role->update($item);  
  } else {
    Role::create($item);
  }
}

Shorter version – with updateOrCreate():

foreach ($items as $item) {
    Role::updateOrCreate(['id' => $item['id']], $item);
}

Actually, same will help if you want to add more roles later in the project, just add the third array item and pretty safely run php artisan db:seed again.

Credit to: https://bit.ly/3oa6z56