Why Laravel 4's Seeds and Migrations Are Damn-powerful Tools
Join the DZone community and get the full member experience.
Join For FreeI used to look at Laravel’s migrations as shortcuts for creating tables quickly without having to write any SQL. In a bigger environment, I saw the usage of it as a way of “versioning” the database schema. Yet, I found another great usage for migrations, especially along with seeds.
First of all, how are you supposed to use migrations?
“Versioning”
Migrations are great because they allow you to track changes on how your database is set up, step-by-step, and update or roll back those changes. For example, if you add a new table, that’s a migration. If you drop a table, that’s a roll back on a migration. If you want to add a new column to a table, you can easily set up a migration for that, as well as a rollback to delete that extra column.
Here’s what a migration looks like:
<?php use Illuminate\Database\Migrations\Migration; class CreateUserTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function($table) { $table->increments('id'); $table->string('email')->unique(); $table->string('username'); $table->string('name'); $table->string('password'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('users'); } }
The “up()” function specifies what to do when you enact your migration (via command line and Artisan) and the “down()” function tells Laravel how to roll back. The migration features go further, you can:
- create indices
- create foreign keys
- add/remove/rename columns
On top of that, you can pretty much specify whatever you want the migration to do, including moving data and running raw queries.
What’s great with “down()” is the reversal of whatever you just did. OK, so what?
Well, on big systems, you can launch features and have a reversal ready right away, similar to how you can undo a commit on a Git repository and deploy.
Seeding
All right, so, seeding is exactly what it sounds like. You add data to your tables. Yes, you can do it via migrations but that’s a bad practice since that would interfere with your production data. Imagine adding sample data to your system every time you run a migration. Not a good practice at all. So this is where seeding comes in. Seeding is actually meant more for the testing environment.
Instead of sampling live data, you can use Seeds to work. You can seed every table with as much data as you want. Laravel will take the seeds and place them in your database so you’re ready to go (seeding is done via command line and a file). Here’s what a seeding file looks like:
<?php class UserTableSeeder extends Seeder { public function run() { DB::table('users')->delete(); $user = new User; $user->fill(array( 'email' => 'antonin@antjanus.com', 'username' => 'antjanus', 'name' => 'Antonin Januska' )); $user->password = Hash::make('admin'); $user->save(); } }
Phew, so, let’s go over this real quick. This is my User Table Seeder. First, notice that the first thing my seeder does is delete all existing data. This is a good thing but not a necessary thing. The reason I would do this is because every time I run the seeder, I effectively duplicate my data. Why would I run the seeder multiple times? Because every time I make a migration, I want the testing data to be ready. So, yeah, delete all rows in a table. I use Laravel’s Eloquent ORM to create an object based on my user model, use mass assignment (don’t forget to enable it!), and save it to the database.
Every time I run my seeder, this is what I run:
<?php class DatabaseSeeder extends Seeder { public function run() { $this->call('UserTableSeeder'); $this->command->info('User table seeded!'); $this->call('LinkTableSeeder'); $this->command->info('Link table seeded!'); $this->call('PostTableSeeder'); $this->command->info('Post table seeded!'); } }
Check this out: When I run the seeder via command line, I get feedback when the seeding is done. This is the DatabaseSeeder file that gets run. You can skip out on seeds and add new seeds when it makes sense to. For example, if you just dropped a table, there's no reason to keep seeding it (because you’d get an error) so you delete the line. You can still keep the original seeder file in case you want to roll back your migration (and add the table back).
This is an example from when I ran two migrations for my project: links and posts. Then I seeded my tables.
Where does that lead us?
The ultimate testing environment is reproducible on different platforms. If you ever clone a repo of mine that features Laravel with migrations or seeds, there’s no reason for you to download an SQL file or run some weird script. Everything’s built in. With a few commands, you can:
- run all migrations, creating all tables, indices, foreign keys, and everything else
- run all seeders and populate all your tables to be supplied with ready testing data
There's no more need for creating “testing posts” for your blog, running SQL queries to fill your DB with random data. You have a unified environment. What’s even better? You can play around with the database, add data, use your stuff and then RESET.
Yep, once you’re done playing around, just roll back your migrations, run them again and you’re ready with a fresh database. Run the seeder again and you’re ready to keep working.
This means that your environment is pretty much indestructible. You’re not tied to a production database and you’re not stuck downloading or uploading large SQL files or copies of your production database. You’re basically “stuck” running two commands and letting Laravel do everything. Wait, wait, let’s make it simpler:
php artisan migrate:refresh --seed
This little command rolls back ALL of your migrations, migrates them again AND seeds your database. It’s the ultimate “refresh”. ;D
I’ve been playing around with this for a while.
What about other frameworks?
Of course, this is not unique to Laravel. I first encountered this with Symfony, which also has migrations and “fixtures”, which are basically “seeds”.
So … how do you do this?
It’s simple. Laravel’s documentation is pretty good at explaining everything but here’s the quick overview. Don’t forget the requirements:
- command line access to Laravel
- PHP access via command line
Creating a Migration
The first step is creating a migration. All this requires is a single command for Artisan (the command line tool for Laravel):
php artisan migrate:make create_your_table
This will create a file in your app/database/migrations folder named “create_your_table” with a time stamp. You may want to be more semantic than that in your project. Open your file up and fill it in with:
<?php use Illuminate\Database\Migrations\Migration; class CreateUserTable extends Migration { public function up() { Schema::create('users', function($table) { $table->increments('id'); $table->string('email')->unique(); $table->string('username'); $table->string('name'); $table->string('password'); $table->timestamps(); }); } public function down() { Schema::drop('users'); } }
Go ahead and read over the Schema documentation on Laravel to get a better idea of the versatility you get with migrations. Great! Notice that I used my previous “user” example named CreateUserTable (create_user_table in the command line).
Migrate
OK, time to migrate your data.
php artisan migrate
You should get either a success or an error message in regard to your migration. If this is your first migration, Laravel will also create a “migrations” table that details the names and batches of migrations run. In case you create five different migrations and migrate them at once, they’ll be grouped in a “batch” and thus will be rolled back together. This is useful if your migrations depend on each other for functionality.
Create a Seeder
For seeding, you’ll have to create your own file like so:
<?php class UserTableSeeder extends Seeder { public function run() { DB::table('users')->delete(); $user = new User; $user->fill(array( 'email' => 'antonin@antjanus.com', 'username' => 'antjanus', 'name' => 'Antonin Januska' )); $user->password = Hash::make('admin'); $user->save(); } }
Again, make sure the class name makes sense. Also, make sure you already have a model built! Save this file in the database/seeds folder. Next, add a reference to this class in the DatabaseSeeder:
<?php class DatabaseSeeder extends Seeder { public function run() { $this->call('UserTableSeeder'); $this->command->info('User table seeded!'); } }
Make sure you add that little bit to let you know if the database has been seeded. It’s nice feedback info.
Seed!
Last thing, run your seed command!
php artisan db:seed
Done!
Published at DZone with permission of Antonin Januska. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Top 10 Pillars of Zero Trust Networks
-
Clear Details on Java Collection ‘Clear()’ API
-
Cypress Tutorial: A Comprehensive Guide With Examples and Best Practices
-
Testing Applications With JPA Buddy and Testcontainers
Comments