So the other day I was doing some work on a relatively fresh Laravel project and because it was just me working on it at the time, I was editing migrations directly and doing fresh migrates & seeding regularly to test different scenarios. It's quite a satisfying setup to be able to test something (in the browser or whatever) which results in data being modified in some way - and then hitting a command to jump your database back to the state before performing said action.
As I was doing some testing, I encountered a problem which only cropped up as I was playing around with things in the browser. This was a bug that definitely needed fixing but I wanted to finish the feature I was working on before swinging back round to it. I wanted my database to revert back to a fresh migrate & seed it with my test data but didn't want to have to go through the steps again when I come back to fixing the aforementioned bug.
I thought of a few ways I could've handled this situation:
None of these felt as smooth as I'd have liked so I started looking into the concept of "reverse seeding" which turns existing data into seed classes. I stumbled upon a fantastic package called iSeed by Orangehill which was just what I was after.
You can run a simple command which will generate a seed file for each of the specified tables, based off of the data present in your default database connection:
php artisan iseed my_table,another_table
As far as I'm aware, there's no way to generate seeders for every table without explicitly listing them one-by-one which isn't the worst, but I think in my ideal setup I'd like to be able to just dump out the entire database without thinking too much about it. Someone did, however, kindly share their custom workaround which passes every table to the iseed command without having to be explicit about naming them.
I decided to take this a step further and create a little composer package which piggybacks off iSeed and serves as a step-in replacement for Laravel's
artisan migrate:fresh --seed but with some additional quality of life features.
The idea is that I can continue with that same workflow of refreshing and re-seeding the database entirely - but at any given time, be presented with an interface for creating a named snapshot of seeders and selectively choose which 'scenario' to run when seeding the database.
The basic gist of it, is you run the following command:
php artisan seed:migrate
which presents you with a dialog option to create a set of seeders from your existing data before eventually calling
artisan migrate:fresh --seed. Along the way, you can also opt-in to run a group of seeders that you may have generated during a previous run-through of this command, run a single specific seeder class or just go with the default behaviour - which is to run
Should you want to generate a snapshot without migrating or seeding anything, there's an alternative command:
php artisan seed:generate
and finally, a cleanup utility to make it easier to delete generated groups of seeders:
php artisan seed:delete
For more information on what this package has to offer, checkout the repo for Better Migrate Seed.