If you have 10 rows of data in the initial Seeder file, but then you need to import 10 more rows when the project is already launched, what should you do? There are a few options.
Imagine the scenario that you have 3 Roles, but then at some point, you decide to add 3 more.
database/seeders/RoleSeeder.php:
use App\Models\Role; class RoleSeeder extends Seeder{ public function run() { Role::create(['name' => 'Administrator']); Role::create(['name' => 'Editor']); Role::create(['name' => 'User']); }}
So, in this case, you have an Administrator, Editor, and User.
But, a month after the project is launched, the client wants to have more roles: Publisher, Viewer, and Commenter. Where do you put them?
And, an even more important question: how do you automatically launch that seed/command on all possible server environments (live/staging/etc), including the local ones for your teammates?
Option 1. Create a new Migration
Yes, you've read it correctly: migration for the data, not for the schema structure.
The migration file has an up()
method where you can do whatever you want, not just Schema::create()
.
And the migration php artisan migrate
is a typical command to run for everyone when pulling the new changes, including deployment to live server and automatic CI/CD and testing process with tools like GitHub Actions.
So, it's the most convenient and logical place to ensure that all server environments would have that data.
php artisan make:migration seed_roles
database/migrations/xxxxxxx_seed_roles.php:
use App\Models\Role; return new class extends Migration{ public function up() { Role::create(['name' => 'Publisher']); Role::create(['name' => 'Viewer']); Role::create(['name' => 'Commenter']); }};
Notice: if you want to make sure that this Role record doesn't already exist in the database, you may run this with firstOrCreate()
:
Role::create(['name' => 'Publisher']); Role::firstOrCreate(['name' => 'Publisher']);
Option 2. Create a New Seeder
If you want more control over who/when launches the new seeds you may create them as a separate Seeder file.
php artisan make:seeder ExtraRoleSeeder
database/seeders/ExtraRoleSeeder.php:
use App\Models\User; class ExtraRoleSeeder extends Seeder{ public function run() { Role::firstOrCreate(['name' => 'Publisher']); Role::firstOrCreate(['name' => 'Viewer']); Role::firstOrCreate(['name' => 'Commenter']); }}
Then, you add that Seeder to the main DatabaseSeeder.php
file, so the next time someone installs the project for the first time, they would have those new roles, too:
database/seeders/DatabaseSeeder.php:
class DatabaseSeeder extends Seeder{ public function run() { $this->call(ExtraRoleSeeder::class); }}
But when someone wants to launch that seeder manually, they do this:
php artisan db:seed --class=ExtraRoleSeeder
Option 3. Add Data Manually
Maybe you want to add the data but not necessarily on all the server environments, only on the live server? Then don't even bother creating more seeders or migration files, like above.
Just go directly to the DB client or your admin panel and add new roles there.
After all, it's a live project at the moment, with data changing in live mode, too. Not everything should be automated for the future.
Very helpful, thanks
putting the creation of roles inside the migration or seeder file is very clever! i prefer the latter though (option 2) as it allows for more control. thanks Povilas!
A fourth option would be to have, in the administrative part of the system, the option to add/edit/delete new rules
Yes, but if you need to add 10 new records, for ALL possible servers in the future, including local environment for every developer, would administrator add that manually for everyone?
We are using updateOrCreate() method in the seeders in our project. Anytime new role needs to be added, we simply add it to the seeder and run db:seed --class=xyz. Do you find anything bad about this approach except that our timestamps get updated for the older existing models probably?
If you can do it and re-run seeders then it's totally fine. But for some systems that have it automated, it's not an option.