Laravel テーブルやカラムに設定したコメントから翻訳ファイルを生成してみた

Laravel で開発していてマスタ管理画面を作っていると、表のタイトル部分、翻訳ファイルを作ったりが面倒だったので、migrationにカラムのコメントは全部設定しているし、これを使って翻訳ファイルを生成したら楽だよなーと思って、方法を模索してみました。

`migration` は以下のように全部コメント入れなきゃいけませんが、後々メンテナンスとか考えると、コメントはいれておくべき。（もちろんMySQL限定ですが）

```php

    public function up()
    {
        Schema::disableForeignKeyConstraints();

        Schema::create('companies', function (Blueprint $table) {
            $table->bigIncrements('id')->comment('会社ID');
            $table->string('name', 64)->comment('会社名');
            $table->timestamp('created_at')->nullable()->comment('作成日時');
            $table->timestamp('updated_at')->nullable()->comment('更新日時');
            $table->softDeletes()->comment('削除日時');

            $table->unsignedBigInteger('created_by')->nullable()->comment('作成者');
            $table->unsignedBigInteger('updated_by')->nullable()->comment('更新者');
            $table->unsignedBigInteger('deleted_by')->nullable()->comment('削除者');

            $table->foreign('created_by')->references('id')->on('users');
            $table->foreign('updated_by')->references('id')->on('users');
            $table->foreign('deleted_by')->references('id')->on('users');
        });

        DB::statement("ALTER TABLE `companies` COMMENT '会社'");

        Schema::enableForeignKeyConstraints();
    }
```

翻訳ファイルを生成するのは  artisan コマンドを拡張してみます。

```bash
php artisan make:command Translation
```
でファイルを作成します。
`app/Console/Commands/Translation.php`

が作られるので、これを編集する。
それで、作ったのがこれ。

```php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Lang;

/**
 * artisanコマンド拡張: 翻訳ファイルをDBの提示から生成する
 *
 * Class Translate
 * @package App\Console\Commands
 */
class Translate extends Command
{

    /**
     * 出力先パス
     * @var string|null
     */
    private $path = null;

    /**
     * タブインデントに使用する文字列
     * @var string
     */
    private $tab = '    ';

    /**
     * テーブルのコメント
     * @var array
     */
    private $tables = [];

    /**
     * カラムのコメント
     * @var array
     */
    private $columns = [];

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'make:translation {--force}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate language files from DB definitions.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $this->path = sprintf('%s/resources/lang/%s/'
            , \App::basePath()
            , \App::getLocale()
        );
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        Artisan::call('config:clear');

        // 上書き
        $force = $this->option('force');

        if ($force && !$this->confirm('Do you wish to overwrite? [y|N]')) {
            echo 'exit.' . PHP_EOL;
            return;
        }

        $tables = DB::table('information_schema.TABLES')
            ->select(['TABLE_NAME', 'TABLE_COMMENT'])
            ->where('TABLE_SCHEMA', env('DB_DATABASE'))
            ->where('TABLE_TYPE', 'BASE TABLE')
            ->where('TABLE_NAME', '!=', 'migrations')
            ->orderBy('TABLE_NAME')
            ->get();

        $tables->each(function ($table) use (&$buffer_tables, &$buffer_columns) {

            $this->tables[$table->TABLE_NAME] = $table->TABLE_COMMENT;

            DB::table('information_schema.COLUMNS')
                ->select(['TABLE_NAME', 'COLUMN_NAME', 'COLUMN_COMMENT'])
                ->where('TABLE_SCHEMA', env('DB_DATABASE'))
                ->where('TABLE_NAME', $table->TABLE_NAME)
                ->get()
                ->each(function ($column) use ($table, &$buffer_columns) {
                    $this->columns[$table->TABLE_NAME][$column->COLUMN_NAME] = $column->COLUMN_COMMENT;
                    $buffer_columns[] = sprintf("\t\t'%s' => '%s',"
                        , $column->COLUMN_NAME
                        , $column->COLUMN_COMMENT
                    );
                });
        });

        // テーブル
        $old = is_array(Lang::get('tables')) ? Lang::get('tables') : [];
        $script = ($force) ? $this->tables : array_replace_recursive($this->tables, $old);
        $this->write($script, 0, 'tables.php');

        // カラム
        $old = is_array(Lang::get('columns')) ? Lang::get('columns') : [];
        $script = ($force) ? $this->columns : array_replace_recursive($this->columns, $old);
        $this->write($script, 0, 'columns.php');

        $this->info('success.');
    }

    /**
     * ファイルを書き出す
     * @param array $arr
     * @param int $indent
     * @param string|null $file
     */
    private function write(array $arr, int $indent = 0, string $file = null)
    {
        $res = [];
        $res[] = '<?php';
        $res[] = '';
        $res[] = '/**';
        $res[] = sprintf(" * resource/lang/%s/%s", \App::getLocale(), $file);
        $res[] = ' * Generated by artisan make:translate';
        $res[] = ' */';
        $res[] = sprintf('return %s;', $this->makeScript($arr, $indent));
        $res[] = '';
        $buffer = implode(PHP_EOL, $res);
        file_put_contents($this->path . $file, $buffer, LOCK_EX);
    }

    /**
     * コードを生成する
     * @param $arr
     * @param int $indent
     * @return string
     */
    private function makeScript($arr, int $indent = 0)
    {
        if (is_string($arr)) {
            return sprintf('\'%s\'', $arr);
        }
        $res = [];
        $indent++;
        $res[] = str_repeat($this->tab, $indent - 1) . '[';
        foreach ($arr as $k => $v) {
            $res[] = sprintf("%s'%s' => %s,"
                , str_repeat($this->tab, $indent)
                , $k
                , $this->makeScript($v, $indent)
            );
        }
        $res[] = str_repeat($this->tab, $indent - 1) . ']';
        return trim(implode(PHP_EOL, $res));
    }
}
```

`php artisan list` に `make:translation` が表示されることがかくにんできれば、
migrateを実行した後で  `php artisan make:translation` を実行すれば、`resources/lang/ja/` 以下に、`columns.php`と`tables.php` が生成されます。