はじめに
データベースにマスタデータをセットしたい。
でも件数が多い・・・となるとバッチ処理を書くしかない。
それでもバッチ処理はfluentに書きたい!そんなあなたに。
Laravelではコマンドラインツールの開発も支援しているようです。
やりたいこと
ローカル側のCSVファイルを、コマンドラインツールを利用してDBにセットアップする処理を行いたい。
構成図
環境
Name | version |
---|---|
Laravel | 5.1 |
MySQL | 5.7.17-0ubuntu0.16.04.2 |
PHP | 7.1.4-1 |
artisan | 5.1.46 (LTS) |
ローカル側からDBを呼び出す際の注意点
port番号が変わります。
Homestead上のMySQLポートは3306ですが、コンソール側から接続する際は33060で繋ぐ必要があるようです。
対応
色々対応は考えたんですが、
- ssh接続してサーバー側からコマンドラインツールを実行する
- →ローカルのCSVファイルをサーバー側に認識させる必要があり
面倒くさそう - Homestead側のポートを3306から33060に変更して統一する
- →セキュリティ面やら実行環境やらが変わって逆に大変そう
ということで、コンソールから実行した場合にはport=33060、サーバー側で実行した場合にはport=3306で起動できるように切り分けを行うことにしました。
config/database.php
の文頭にこれを記述しましょう。
2017/08/02修正 : port判定の厳格化
/**
* 修正前:ssh接続後、Homestead上コンソールから
* $ php artisan migrate
* でも実行しようものなら
* [PDOException]
* SQLSTATE[HY000] [2002] Connection refused
* エラーが発生する不具合を修正
*/
/*
$port = 3306;
if (php_sapi_name() == 'cli')
{
$port = 33060;
}
*/
$port = 3306;
$ip = gethostbyname(gethostname());
/**
* クライアント側からの接続で、かつipアドレスがサーバー自身でなければportに33060を設定
*/
if (php_sapi_name() === 'cli' && $ip !== '127.0.0.1')
{
$port = 33060;
}
また、各DBの設定条件に'port'=>$port
を追記してください。
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'port' => $port,
],
これによってコンソール側から接続する際はport=33060
で、ローカル側から接続する際はport=3306
で接続できるようになりました。
ここまで設定できれば、いよいよコマンドラインツールの開発を進めていくことができます。
事前準備
Commandファイル生成
php artisan
からコマンドラインツールを生成することができます。
$ php artisan make:console SampleCommand --command=sample
--command
オプションで、実行時の名前を設定することもできます。
ちなみにここで、--command=samplegroup:sample
としておけば、samplegroup
としてグループ化を行ってくれます。
成功していれば、app/Console/Commands/SampleCommand.php
ファイルが生成されていることと思います。
Commandへのパスを登録
これだけではphp artisan sample
を叩いてもコールできません。
app/Console/Kernel.php
にartisanコマンドとして登録してあげます。
protected $commands = [
Commands\Inspire::class,
Commands\Sample::class, //この行を追加する
];
念のため登録後、php artisan list
コマンドを叩いて新しく追加したコマンドが登録されているかどうかを確認します。
処理実行
では、実際にSampleCommand.php
にテストコードを記述して処理が実行できるか確認してみましょう。
namespace App\Console\Commands;
use Illuminate\Console\Command;
class Sample extends Command
{
protected $signature = 'sample';
protected $description = 'Command description';
public function __construct() {
parent::__construct();
}
// 実際の処理はhandle内に記述していく
public function handle() {
$this->info('Processing start.');
$progressBar = $this->output->createProgressBar(5);
$i = 0;
while ($i++ < 5) {
sleep(1);
$progressBar->advance();
}
$progressBar->finish();
echo "\n";
$this->info('Processing end.');
}
}
$ php artisan sample
Processing start.
5/5 [============================] 100%
Processing end.
もちろんLaravelの機能を利用しているため、Model、ServiceProviderなど、普段使っている機能はすべて利用できます。
Commandクラスでは対話的な処理用のクラスも充実しているみたいなので、色々と使い勝手が良さそうです。
参考
以下の文献を参考にさせていただきました。
所感
最初は自分で、素のPHP書いてましたがモデル使いたいなーと思って調べてたらとても簡単に実装できました。簡単すぎてびっくりするほどに。
ビジネスロジックをProviderに記述してしまえばテストも簡単になりますね。
何より個人的にはプログレスバーを簡単に実装できるのが気に入りました。