Laravel Migrations — Maintaining sanity

How to not shoot yourself in the foot with table names

Ikechi Michael
3 min readApr 19, 2018

Migrations are so cool!

If this came to mind, this article probably isn’t for you

They’re like version-control for your databases … You can see how your database morphed into what it is today from what it was in the beginning, as well as perform operations like rollbacks when something goes awry.

Migrations in Laravel — a crash course

Laravel makes migrations even easier, with a standard approach via migration classes that are generated with the

php artisan make:migration sample_migration

command.

This generates a class in the databases/migrations directory that looks like

The up and down methods are supposed to contain code to perform the migration, and rollback the migration respectively.

But this is stuff you probably already know, and if you don’t, you should definitely check out the latest official docs entry on migrations.

The problem (?)

When creating a table in a migration, you’d have code in the up function like

Schema::create('sample_migrations', function (Blueprint $table) {// add columns to the users table here});

and when modifying the sample_migrations table in a different migration, you’d have

Schema::table('sample_migrations', function (Blueprint $table) {// add code to modify columns and their relationships});

In a large project, you could have thousands of migration scripts as your database structure changes over the duration of the project.

Referencing the table name directly like this could pose an issue, as the name of a table is determined by the Laravel Model class associated with it.

What do you do to all the migration scripts when sample_migrations is no longer a fitting name for this table? Perhaps find and replace?

or

How does a new member of the team know which model is associated with the sample_migrations table?

Fret not! A few alternatives present themselves.

Alternative #1: A ModelTableName trait

In your app/Traits directory (create one if non-existent), add a ModelTableNameTrait.php file and place this code in it.

This trait will add a static name() method to laravel model classes that implement it. This method will get and return the actual table name that the model class represents.

So, SampleMigration::name() will return sample_migrations by default, but if you added

protected $table = 'my_sample_migrations'; 

to the model class to override its default table name, then SampleMigration::name() would return my_sample_migrations instead.

To useModelTableNameTrait in your SampleMigration model,

Now, theSampleMigration model would have the name() static method that can be used anywhere, especially in a migration class like

This makes it immediately obvious that the table being processed is related to the SampleMigration model, and helps keep our migration scripts sane in the long run.

Alternative #2: extend a BaseModel

If making sure every model uses the ModelTableNameTrait just doesn’t appeal to you, and you’d rather solve the problem once and for all, I recommend having a BaseModel class that extends Illuminate\Database\Eloquent\Model and uses the ModelTableNameTrait.

If all your models extend that BaseModel class, they’ll have all its static and non-static properties and methods, which means they’d have the trait too.

Of course, this is a double edged sword, you should be very careful with.

Make sure you don’t add methods or properties that override ones already used in Illuminate\Database\Eloquent\Model or you’d start wondering why your application behaves funny (or not so funny, tbh).

--

--

Ikechi Michael
Ikechi Michael

Written by Ikechi Michael

I’ve learned I don’t know anything. I've also learned that people will pay for what I know. Maybe that's why they never pay.