ER図からテーブル定義書やマイグレーションファイルを爆速で自動生成する方法

# はじめに
みなさんはER図を書く際、何を使って書いてますか？
私自身、Excelであったり、draw.ioなどの作画ツールであったり、いろいろ試してきましたが、どれも作るのに時間がかかってしまっていました。
視覚的にサクッとER図を書けて、なおかつそれをテーブル定義書としても出力できたら便利ですよね。
ということで、それを実現するための方法をフローにまとめてみました。

# ER図をUMLで記述する
UMLと聞くとクラス図などの作画などに使われることが多いですが、実はER図を書くこともできます。
PlantUMLではバージョン1.2017.08 からER図に対応しています。
テキストで書くことができるので編集は楽ですし、PhpStormなどを利用すればリアルタイムで確認しながらER図を書くことができます。
テキストファイルですのでgit管理やドライブ管理なども容易ですし、共同作業にとても向いています。

- PhpStormでER図を書く時に便利なプラグイン
    - PlantUML integration 
        - https://plugins.jetbrains.com/plugin/7017-plantuml-integration
    - ビュー表示を行うために必要なツール
        - https://www.graphviz.org/

- 参考
    - https://qiita.com/Tachy_Pochy/items/752ef6e3d38e970378f0 
    - https://qiita.com/ot-aoyagi/items/d2bfbff219c592822d53

# ER図のUMLのテンプレート
テーブル定義書を自動生成するためには一定のレギュレーションにそってUMLを記述する必要があります。
以下、そのテンプレートです。

```sample
@startuml

'区分罫線を非表示
hide empty members

'マークと背景色の定義
!define master_data_db #E2EFDA-C6E0B4
!define user_db #FCE4D6-F8CBAD
!define MASTER_DATA AAFFAA
!define User FFAA00

'設定職を定義
skinparam class {
    BorderColor Black
    ArrowColor Black
}

package "ユーザー管理" as user {
    entity "accounts [アカウント]" as accounts <<U, User>> user_db {
        + id : bigInteger [ID]
        # user_id : bigInteger [ユーザID]
    }

    entity "users [ユーザー]" as users <<U, User>> user_db {
        + id : bigInteger [ID]
        # user_id : bigInteger [ユーザーID]
        total_exp : integer [取得経験値]
    }

    entity "rank_details [ランク詳細]" as rank_details <<M, MASTER_DATA>> master_data_db {
        + id : integer [ID]
        rank : integer [ランク]
        exp : integer [累計exp]
    }
}

'関係図を定義
users        ||-up-||     accounts

'テーブルメモ
note right of rank_details : メモです
@enduml

```

# 記述ルール
テーブル定義書をUMLから自動生成する機能を利用する場合、サンプルのように一定のルールに則った記述が必要です。

```sample2
    entity "rank_details [ランク詳細]" as rank_details <<M, MASTER_DATA>> master_data_db {
        + id : integer [ID]
        rank : integer [ランク]
        exp : integer [累計exp]
    }
```

上記のentity1つ分がテーブル定義1つに対応しています。
rank_details部分がテーブル名になります。
[]でくくられた部分がテーブル名の日本語部分になります
asの後ろ部分はテーブル名と同一にして下さい。
MASTER_DATA部分はデータベースの分類にあたります。種類ごとでグルーピングして下さい。
同じグルーピングのものは同じスプレッドシートに定義書出力されます。
master_data_dbはコネクション名になります。
integer部分はカラムの型定義になります。
カラム名の前に-を付けると、実カラムとして扱われなくなります。


# Spreadsheetのライブラリを利用
- 下準備
    - GoogleDriveに「Componet」「OutPut」「UML」というディレクトリを生成します
    - UMLというディレクトリの中にはER図を記述したファイルを入れておきます

- ライブラリの設定
    - Spreadsheetを作成し、ツール⇒スクリプトエディタを選択しエディタを起動します
    - リソース⇒ライブラリ⇒1T1I-tXjjcsbBqCo_LiQtuvQo9MGq6rVMxad9k13Nw-Cc53bHT9-ySVFBと入力し、最新バージョンを選択します

ライブラリを読み込むと、ER図の読み込み、テーブル定義書のYaml出力、マイグレーションファイルの出力を行うための関数が使えるようになります。


## ER図の読み取り（UMLディレクトリ内のものを読み込む）
```sample3
function umlLoad()
{
    CreateApiTool.syncUML('***********');
}
```
***部分にはGoogleDriveのUMLディレクトリのフォルダIDを指定して下さい。
なお、スプレッドシートのタイトルとUML記述のデータベースの分類テキストが同一のもののみを出力されるようになっています。
また、UMLのファイル名とスプレッドシートのシート名が対応するようになっています。

- フォルダIDとは 
    - https://tonari-it.com/gas-google-drive-file-folder-id/#toc3


## テーブル定義書をYamlやマイグレーション形式で出力

```sample4
function createTable()
{
    CreateApiTool.singleOutputTable('AAA', 'BBB', 'table_main.txt', 'table_sub.txt');
}

function createMigration()
{
    CreateApiTool.singleOutputMigration('AAA', 'BBB', 'table_migration_main.txt', 'table_migration_sub.txt');
}
```
AAAにはマイグレーションファイルやYamlファイルを出力させたいフォルダIDを指定して下さい。
OutPutというディレクトリを作成し、そのフォルダIDを指定すると良いでしょう。
また、Componetというディレクトリには、以下のようなテンプレートファイルを保存し、BBBには、そのフォルダIDを指定します。

なお、第3引数、第4引数には、出力する際のテンプレートテキストのファイル名を指定します。
テーブル定義書は真ん中の縦の空白スペースを基準にMainとSab部分に分けられており、それぞれの内容をどのような形式で出力するかを指定することができます。
基本的にはSpreadsheetの1行目の名称と@のキーが対応しており、その部分が置き換わって出力されます。
例外としてspreadsheetTileNameはスプレッドシートのタイトル名として使うこともできます。
また、キーの語尾にSnakeCaseやPascalCase、CamelCaseと付けるとキーワードに応じた変換を加えることができます。

```table_main.txtのサンプル
- table_name: '@TableNamePascalCase'
  table_description: '@TableDescription'
  database_directory_name: '@spreadsheetTileNamePascalCase'
  description: '@ConnectionName'
  columns:
```

```table_sub.txtのサンプル
    - name: '@ColumnName'
      description: '@ColumnDescription'
      data_type: '@DataType'
```

```table_migration_main.txtのサンプル
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class @TableNamePascalCaseTable extends Migration
{
    /**
     * マイグレーション実行
     *
     * @return void
     */
    public function up()
    {
        Schema::create('@TableNameSnakeCase', function (Blueprint $table) {
            @attributes
            $table->timestamps();
        });
    }

    /**
     * マイグレーションを元に戻す
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('@TableNameSnakeCase');
    }
}
```

```table_migration_sbu.txtのサンプル
$table->@DataType('@ColumnName')@IsUnsigned@IsNullable->comment('@ColumnDescription');
```


# 番外編
自動出力機能はテンプレートファイルさえ変更すれば、様々な用途にも使用できますが、LaravelのAPI定義書を作ろうとした際、APIはRequestとResponseがあったため通常の方法では対応することができませんでした。
そこで、別途Laravel用のAPI定義書からYamlファイルを自動出力する関数も用意しましたので合わせて活用してもらえると幸いです。

## 下準備
Laravelのフォームリクエストの日本語部分を管理するためにRequestRuleというシートを用意し、そのシート内に以下のようなバリデーションメッセージテキストを用意します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577121/c531b822-3632-7ebf-e2cd-6a50a76bc37d.png)

## テーブル定義書をYamlで出力
AAAには出力先のフォルダID、BBBにはテンプレートが入っているフォルダのフォルダID、第3引数以降はテンプレートのファイル名を指定します。
第7引数にはバリデーションルールを指定するカラム名と入力します（任意の名前に変更可能）。

```sample5
function createTable()
{
    CreateApiTool.singleOutputApi('AAA', 'BBB', 'api_main.txt', 'api_sub.txt', 'api_request.txt', 'api_response.txt', 'RequestRule');
}
```

```api_main.txtのサンプル
- controller_name: '@spreadsheetName'
  route_prefix: '@spreadsheetTileNameSnakeCase'
  http_method: '@HttpMethod'
  name: '@ApiName'
  description: '@HttpDescription'
```

```api_sub.txtのサンプル
      - name: '@ColumnName'
        description: '@ColumnDescription'
        data_type: '@DataType'
        default_value: '@DefaultValue'
        is_required: '@IsRequired'
        rules: '@RequestRule'
        messages: {@messages}
```

```api_request.txtのサンプル
  request:
    columns:
```

```api_response.txtのサンプル
  response:
    columns:
```

# サンプルシート
- テーブル 
    - https://docs.google.com/spreadsheets/d/1ET2OtyGdihwliJ1Ue0ZYXgPNkWFnwuC2Sgt7V__WWDc/edit?usp=sharing
- API
    - https://docs.google.com/spreadsheets/d/19nj4qV-_BXVozOP6iHThoMT0zZiAOK7OIMum1eIeqp8/edit?usp=sharing