[Laravel5.1]バッチ処理用のコマンドラインツールを簡単に作成する

#はじめに
データベースにマスタデータをセットしたい。
でも件数が多い・・・となるとバッチ処理を書くしかない。
それでもバッチ処理はfluentに書きたい！そんなあなたに。
Laravelではコマンドラインツールの開発も支援しているようです。

#やりたいこと
ローカル側のCSVファイルを、コマンドラインツールを利用してDBにセットアップする処理を行いたい。
##構成図
![002.png](https://qiita-image-store.s3.amazonaws.com/0/165355/073e58dc-2429-d15e-df40-a72fe4a3b840.png)
##環境
|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判定の厳格化**

```php:config/database.php
/**
 * 修正前：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``を追記してください。

```php:config/database.php
'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``からコマンドラインツールを生成することができます。

```bash:console
$ 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コマンドとして登録してあげます。

```php:app/Console/Kernel.php
protected $commands = [
    Commands\Inspire::class,
    Commands\Sample::class, //この行を追加する
];
```

念のため登録後、``php artisan list``コマンドを叩いて新しく追加したコマンドが登録されているかどうかを確認します。

#処理実行
では、実際に``SampleCommand.php``にテストコードを記述して処理が実行できるか確認してみましょう。

```php:app/Console/Commands/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.');
    }
}
```

```text:実行結果
$ php artisan sample

Processing start.
 5/5 [============================] 100%
Processing end.
```

もちろんLaravelの機能を利用しているため、Model、ServiceProviderなど、普段使っている機能はすべて利用できます。
Commandクラスでは対話的な処理用のクラスも充実しているみたいなので、色々と使い勝手が良さそうです。

#参考
以下の文献を参考にさせていただきました。

+ [Laravelでコマンドラインアプリケーションを作成する](http://qiita.com/nenokido2000/items/abbf70c87c9ad86a2b89#%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF)
+ [Laravel5.1 Artisan コンソール](https://readouble.com/laravel/5.1/ja/artisan.html)

#所感
最初は自分で、素のPHP書いてましたがモデル使いたいなーと思って調べてたらとても簡単に実装できました。簡単すぎてびっくりするほどに。
ビジネスロジックをProviderに記述してしまえばテストも簡単になりますね。
何より個人的にはプログレスバーを簡単に実装できるのが気に入りました。