##はじめに
今回は、表題の方法を解説していきます。
「2019_07_05_052836_create_users_table.php」が「____create_users_table.php」のようにスマートになり、マイグレーションの順序も簡単に変更できるようになります。
お急ぎの方は、手順からどうぞ。
また、完成物はGitHubにあります。
##環境
Laravel Framework 8.64.0
##動機
なぜ、こんなことをしたいと思ったのか?理由は主に二つあります。
###その1
Laravelのマイグレーションは、__ファイルの作成日時の順__に実行されます。そのため、外部キー制約などリレーションの関係があるテーブルを複数扱う際に、正しい順序で実行できずにエラーとなってしまうことが多々あるのです。
###その2
Laravelのデフォルトのファイル名形式は「yyyy_mm_dd_xxxxxx_*.php」となっています。 例えば、「2019_07_05_052836_create_users_table.php」のようなものです。
この形式のどこが問題かというと、エディタなどで長いファイル名が省略された際に、どのテーブルについてのファイルかが一眼で判別できないという点です。
##手順
###雛形の作成
はじめに、以下のコマンドを実行し、雛形を作成してください。(今回はmigrate:fresh
とmigrate:refresh
コマンドについてのみ解説します。他のコマンドに関してもベースは同じです。)
php artisan make:command ArtisanMigrateFreshCommand
php artisan make:command ArtisanMigrateRefreshCommand
/app/Console/Commands
の中にArtisanMigrateFreshCommand.php
とArtisanMigrateRefreshCommand.php
があれば成功です。なかった場合は、以下のコードを元に作成してください。
__ArtisanMigrateFreshCommand.php__
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ArtisanMigrateFreshCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'command:name';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
return Command::SUCCESS;
}
}
__ArtisanMigrateRefreshCommand.php__
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ArtisanMigrateRefreshCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'command:name';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
return Command::SUCCESS;
}
}
###雛形をコーディング
次に作成されたそれぞれのファイルについてコードを記述していきます。
まず、コマンド名を決定します。php artisan
の後にくる識別名です。こちらは任意のもので結構なのですが、migrate:fresh
やmigrate:refresh
としてしまうと、エラーとなってしまいます。すでに用意されているものは使用しないようにしましょう。
protected $signature = 'migrate:f {--seed}';
protected $signature = 'migrate:rf {--seed}';
{--seed}
は、マイグレーションと同時にシーディングを行うかのオプションです。
次に、コマンドの説明を設定します。こちらはスルーしても問題ありません。
コマンドでphp artisan list
と打ち、migrate:fresh
とmigrate:refresh
のdescriptionを確認します。
php artisan list
.
.
.
migrate:fresh Drop all tables and re-run all migrations
migrate:refresh Reset and re-run all migrations
これらをそのまま流用します。
protected $description = 'Drop all tables and re-run all migrations';
protected $description = 'Reset and re-run all migrations';
次に、本命の作業です。実行する処理を記述していきます。
handle()
にてそれぞれ以下のようにコーディングしてください。(本来であれば共通する処理はまとめるべきなのですが、今回は省略しています)
// 先頭に記述
use Illuminate\Support\Facades\Config;
public function handle() {
$config = Config::get('migration');
$migrations = $config['files'];
$base_path = $config['base_path'];
$prefix = $config['prefix'];
$suffix = $config['suffix'];
$is_first = true;
foreach ($migrations as $migration) {
$path = $base_path . $prefix . $migration . $suffix;
if ($is_first) {
$cmd = 'migrate:fresh';
$is_first = false;
} else {
$cmd = 'migrate';
}
$this->call($cmd, [
'--path' => $path,
]);
}
if ($this->option('seed')) {
$this->call('db:seed');
}
return Command::SUCCESS;
}
// 先頭に記述
use Illuminate\Support\Facades\Config;
public function handle() {
$config = Config::get('migration');
$migrations = $config['files'];
$base_path = $config['base_path'];
$prefix = $config['prefix'];
$suffix = $config['suffix'];
$is_first = true;
foreach ($migrations as $migration) {
$path = $base_path . $prefix . $migration . $suffix;
if ($is_first) {
$cmd = 'migrate:refresh';
$is_first = false;
} else {
$cmd = 'migrate';
}
$this->call($cmd, [
'--path' => $path,
]);
}
if ($this->option('seed')) {
$this->call('db:seed');
}
return Command::SUCCESS;
}
###カーネルさんに登録する
/app/Console/Kernel.php
に先ほど作成した二つのコマンドを登録します。
protected $commands = [
Commands\ArtisanMigrateFreshCommand::class,
Commands\ArtisanMigrateRefreshCommand::class,
];
###設定ファイルの作成
マイグレーション対象となるファイルを一元管理するファイルです。/database/seeders/DatabaseSeeder.php
と同様の役割を担っている捉えておいてください。
/config/
にmigration.php
を作成し、以下の雛形をコピペしてください。
<?php
return [
'files' => [
],
'base_path' => 'database/migrations/',
'prefix' => '____',
'suffix' => '.php',
];
files
配列内にファイル名を実行したい順に列挙していきます。例えば、
'files' => [
'create_users_table',
'create_plans_table',
'create_admins_table',
]
のような形です。
この形を取ることで、__順序や実行の可否の変更は容易に変更できる__ようになります。
###ファイル名を変更する
最後にファイル名を変更しましょう。
日付部分(yyyy_dd_mm_xxxxxx)を取り除き、先頭にアンダースコア(_)を4つ並べた____**.php
という形式にします。例えば、____create_users_table.php
のような形です。
なお、このアンダースコア4つというのは、/vendor
内の次のコードによるものです。
protected function getMigrationClass(string $migrationName): string
{
return Str::studly(implode('_', array_slice(explode('_', $migrationName), 4)));
}
##おわりに
以下のコマンドをそれぞれ実行してみましょう!
php artisan migrate:fresh
php artisan migrate:fresh --seed
php artisan migrate:refresh
php artisan migrate:refresh --seed
エラーが出なければ、無事成功です。
エラーが出てしまった場合は、
「Kernel.php
にコマンドが登録されているか」
「config/migration.php
にファイルが設定されているか」
「ファイル名が適切に変更されているか」
「その他手順通りに進められているか」
「マイグレーションファイル自体にエラーの原因がないか」
などを確認してみてください。
##GitHub
今回作成したファイルをまとめました。参考にどうぞ。