You can create awesome PHP websites using Laravel. While doing that is really simple, mastering it is a different game. One of the key topics you can quickly see the expertise of a programmer is database migrations. If you are new to migrations, this is a good place to start. However, even if you already use them, this article will take you to a different level. In fact, we will see how to use a Laravel migration to improve your code efficiency and your DevOps lifecycle.
Since we talk about a specific topic of Laravel, we assume you have some basic knowledge of this framework at least. In case you don’t, you can quickly remediate by reading this Laravel tutorial.
What is a Laravel Migration?
The first thing we need to do is clarify what is a Laravel Migration, or database migration. A Laravel Migration is a PHP file that defines how to modify a database. In other words, it may define to create, alter, or delete tables. Of course, you can do all of that with queries in your SQL language (e.g. MySQL), but with migrations, we go a step further. In fact, you don’t write SQL queries in migrations. You just call some specific PHP functions, and they will take care to build the query for you. Laravel builds the query for you, according to the database type. This way, you are independent of the database itself: the same code will work for a MySQL database and for a Microsoft SQL. The only database having limited compatibility is SQLite, but that’s because of its own limitations – not because of Laravel’s.
Talking about the code, a Laravel Migration is simply a class where you customize two methods: up()
and down()
. The up()
function should contain the set of operations to apply the migration. In other words, what needs to be done to apply the changes to the database. Instead, the down()
function must define how to roll back those changes. For rollback, we mean taking a database that already has the changes and removing them – restoring the previous state.
How does it work?
Okay, but how does this work in practice? Let’s take a look at a sample migration file. First, note that all migrations are inside the database/migrations folder within your Laravel project root. You can create a new migration with php artisan make:migration
. This will create a migration with the name specified, prepending the date and time to it. In fact, since migrations alter the database, you want to ensure you apply them in the right order. For example, you may have a migration altering a table: you must ensure that the migration that created that table is run before the one that alters it. Here is an example migration file.
CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('email')->unique();
$table->string('password_hash');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
This migration creates a new table with the Schema::create()
method. We name the new table user, and we define a set of columns (id, email, password_hash). We also add two special columns: created_at and updated_at. Laravel takes care of that for us with the timestamps()
method. If instead, we want to reserve the migration, we completely drop the table.
How can Laravel know, among all the migrations, which ones are yet to apply? It creates an additional service table in the database, named migrations, where it logs all the migrations that were applied. To apply all new migrations, you can use php artisan migrate
. Laravel will check in the database for the migrations that were already applied, and start from the first that wasn’t. You may want to start from scratch, emptying the database and applying all migrations. You can do that with php artisan mgirate:fresh
. We won’t go deep on how to write migrations here, for that you can refer to the official documentation.
A Laravel Migration for DevOps
What about DevOps?
DevOps is one of the most important new trends of IT and development. However, it includes many different concepts, so we should clarify a little bit. With DevOps, you try to make faster the process that takes a piece of code from development to production. This is possible with several automation stages, like continuous integration and continuous deployment (CI/CD). Typically, it translates into having a source control system like GitHub. Then, all developers push code to different branches, and every time a developer updates the master branch, the code gets installed on the production servers. Automatically. We talked about DevOps in this article.
Of course, you need to have some mechanisms to ensure you won’t ship crap code to the production. A good option is a combination of automated and manual tests, but that’s for another day. Let’s just assume you will ship only perfect code to your servers. If you want to automate the process, just shipping the code is not enough. To ensure the code works on a server, you may have to do some of the following things.
- Ship the code to the server
- Move some files into different folders
- Edit the cron jobs
- Modify the registry keys or environment variables
- Run some shell commands
- Update the database
Well, a Laravel Migration allows you to automate the process of updating the database.
The beauty of Laravel Migrations
By writing Laravel Migrations, you are including the database in source control. In other words, you are versioning your database at the same time of versioning your “normal” code. This will make your DevOps process much smoother. However, this comes at a price: you have to write your own migration. In fact, in Laravel you use Models to interact with database records. Still, you don’t define the fields a table needs in the model, you define them in the migration. That’s because the model may evolve over time in the same file. Instead, a migration is something you write once. Need to alter the same model/table? Just add another migration to alter the table, don’t edit the existing migration.
This will result into having many migrations over time, so it is okay if at the very beginning of your development you condensate some information in a few migrations. However, as soon as you have some code running in production, this is not okay anymore. Every change to the database will need its own migration, that’s the only way to ensure you can implement DevOps.
Wrapping it up
With a Laravel Migration, you can integrate the changes to the database in your source control. This will smooth your process of delivering code to the production servers. On top of that, by writing a migration you don’t have to write SQL queries, so you maintain independence from the database. Laravel migrations are a powerful way to work with databases for modern applications, and many frameworks use similar principles. Hopefully, with this article not only you will start to use migrations, but you will use them with some criteria.
What do you think about migrations? Was this article helpful? Let me know your opinions in the comments.