224 words, 2 min read

I often create custom commands to do things like data migrations.

Once scenario that pops up quite often is that I want to check that all database migrations are applied before doing the data migration.

To make this easier from within a console command, I started with creating a trait which can check this.

The basic idea is to run artisan migrate with the --pretend option and checking the output.

namespace App\Traits;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Str;
trait ChecksPendingMigrations
{
public function hasPendingMigrations(): bool
{
if (App::environment('testing')) {
return false;
}
Artisan::call('migrate', ['--pretend' => true, '--force' => true]);
return Str::doesntContain(Artisan::output(), 'Nothing to migrate.');
}
}

Note that when running tests, I'm skipping the check as the migrations are already applied anyway.

Using it inside a custom command is then very easy and can by done by using the trait and calling the hasPendingMigrations function:

namespace App\Console\Commands;
use App\Traits\ChecksPendingMigrations;
use Illuminate\Console\Command;
final class MySampleCommand extends Command
{
use ChecksPendingMigrations;
protected $signature = 'my-sample-command';
protected $description = 'Sample command which checks pending migrations';
public function handle(): int
{
if ($this->hasPendingMigrations()) {
$this->error('Run the pending database migrations first');
return self::FAILURE;
}
return self::SUCCESS;
}
}

A different approach can be to simply apply the migrations instead of checking them. If prefer no to do this as I want to be able to check what is happening.