Yamlファイルを直接手書きすることからの脱却

## はじめに
OSSライブラリなどを使っていると定義はYaml形式で記述するというものが多いですが、手書きするのが面倒くさく視認性があまり良くないのが弱点です。
当記事は、そんな悩みを解消する為のLaravel製ライブラリ「spread-sheet-converter」の解説記事です。
※spread-sheet-converterのREADMEの翻訳及び使い方記事です

## 使用ライブラリ
- spread-sheet-converter  
https://github.com/stepupdream/spread-sheet-converter

## 要件
スプレッドシートコンバータアプリケーションの要件は次のとおりです。

- PHP-サポートされているバージョン：>= 7.3
- Laravel-サポートされているバージョン：>= 6.0

## インストール
```bash
composer require --dev stepupdream/spread-sheet-converter
```

## 準備
このライブラリはGoogleSheetAPIを使用してスプレッドシートの内容を参照しにいくため、API使用のための設定ファイルを事前に用意する必要があります。

1. API実行のための設定ファイルを用意する
https://blog.capilano-fw.com/?p=1816
こちらのサイトなどを参考にcredentials.jsonファイルを用意し、storage/app/json/フォルダに入れます。

2. スプレッドシートの編集メンバーにAPI対象を含める
https://blog.capilano-fw.com/?p=1816#i-3
こちらのサイトを参考にyaml化したい定義が書かれているスプレッドシートの閲覧メンバーに1で用意したJSONファイルの中に書かれているクライアント・メールアドレスを入力します。

3. yaml化したいスプレッドシートのIDを控えておく
https://blog.capilano-fw.com/?p=1816#ID
こちらのサイトを参考にyaml化したい定義が書かれているスプレッドシートのIDを控えておきます。


## 定義ファイル
```bash
php artisan vendor：publish
```
コマンドを実行し、spread-sheet-converterのconfigファイル及びサンプルテンプレートファイルをローカル側に出力します。
なお、テンプレート定義はbladeファイルであるため、[bladeテンプレート](https://readouble.com/laravel/8.x/ja/blade.html)の専用関数が使用可能です。
スプレッドシートに記載した内容を自由に改変した状態でYaml化することができます。

## configファイル
```php
// ↑の準備で用意したjsonファイルの保存場所を指定する。配置場所を変えていなければ基本的には変更不要
'credentials_path'         => storage_path('app/json/credentials.json'),

// API定義をyaml出力する場合に使用する。FormRequestルールを定義している列名を指定する。基本的には変更不要
'request_rule_column_name' => 'RequestRule',

// API定義をyaml出力する場合に使用する。FormRequestルールを定義しているシート名を指定する。基本的には変更不要
'request_rule_sheet_name'  => 'RequestRule',

// 読み込むスプレッドシートを配列形式で設定する
'read_spread_sheets'       => [
[
    // Yaml化したいスプレッドシートのIDを指定する（↑の準備で控えたID）
    // ※実装中のシステムがオープンソースの場合はシートIDはenvファイル化しておきgit管理外とすることを推奨
    'sheet_id'                    => env('READ_SHEET_ID_01', '***************************'),

    // 該当のスプレッドシートを管理するためのユニークな名前を指定する。
    // Yamlファイルの出力コマンドの引数に使用します。
    // ※スプレッドシートのタイトル名と同名にすることを推奨
    'category_name'               => 'MasterData',

    // スプレッドシートがどのような記述方法で書かれているかを指定します
    // 当該ライブラリは3種類のタイプに対応しています。（"SingleGroup"または "MultiGroup"または "Other"）
    'read_type'                   => 'SingleGroup',

    // Yaml出力に使用するbladeファイルのファイル名を指定します
    // bladeファイルは自由に追加することも可能です。自分で作った場合はそのファイル名を指定します
    // ※resouces/DefintionDocument以下で管理されています
    'use_blade'                   => 'single',

    // Yamlファイルを出力するディレクトリ先を指定します
    'output_directory_path'       => base_path('definition_document/database/master_data'),

   // 定義の記述の親と子の区切りとなっている列名を指定します
    'separation_key'              => 'ColumnName',

   // 定義の記述の子グループの区分けをするための列名を指定します
   // ※separation_keyと同じものを指定すること推奨
    'attribute_group_column_name' => null,
],
]
```

## 定義サンプル
[SingleGroupパターン](https://docs.google.com/spreadsheets/d/1RBz_OWf99gg4t0b0PxkkLImg3AzCAduQc88kmYCOiJ8/edit#gid=0)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1490767/6f2ffaa7-0b4f-c905-1821-3506b8a432d2.png)

```yaml
// $parentAttribute->sheetName()にはスプレッドシートのシート名が格納されています
// $parentAttribute->spreadsheetCategoryName()にはconfigで指定したcategory_nameが格納されています
// $parentAttribute->getAttributesGroupByKeyName('*')には子側のデータの配列が格納されています
- name: '{{ $parentAttribute->getParentAttributeDetailByKey('TableName') }}'
  database_directory_name: '{{ $parentAttribute->spreadsheetCategoryName() }}'
  connection_name: '{{ $parentAttribute->getParentAttributeDetailByKey('ConnectionName') }}'
  domain_group: '{{ $parentAttribute->sheetName() }}'
  description: '{{ $parentAttribute->getParentAttributeDetailByKey('TableDescription') }}'
  columns:
@foreach($parentAttribute->getAttributesGroupByKeyName('*') as $attribute)
    - name: '{{ $attribute->getAttributeDetailByKey('ColumnName') }}'
      description: '{{ $attribute->getAttributeDetailByKey('ColumnDescription') }}'
      data_type: '{{ $attribute->getAttributeDetailByKey('DataType') }}'
      migration_data_type: '{{ $attribute->getAttributeDetailByKey('MigrationDataType') }}'
      is_real_column: {{ $attribute->getAttributeDetailByKey('IsRealColumn') }}
      is_unsigned: {{ $attribute->getAttributeDetailByKey('IsUnsigned') }}
      is_nullable: {{ $attribute->getAttributeDetailByKey('IsNullable') }}
@endforeach

```

----
[MultiGroupパターン](https://docs.google.com/spreadsheets/d/1bef99e4UWHBmCVuRvgkayfolBXtL85vC8iN2a8n7GxY/edit#gid=0)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1490767/6d4a3ff1-7fa5-f132-3620-d4fbed48fe67.png)

```yaml
// $parentAttribute->sheetName()にはスプレッドシートのシート名が格納されています
// $parentAttribute->spreadsheetCategoryName()にはconfigで指定したcategory_nameが格納されています
// $parentAttribute->getAttributesGroupByKeyNameでは、引数に指定した子グループの配列を取得できます
// $request_attribute->ruleMessage()には、'RequestRule'に対応したルールメッセージが格納されています
- controller_name: '{{ Str::studly($parentAttribute->sheetName()) }}'
  route_prefix: '{{ Str::snake($parentAttribute->spreadsheetCategoryName()) }}'
  http_method: '{{ Str::studly($parentAttribute->getParentAttributeDetailByKey('HttpMethod')) }}'
  name: '{{ Str::studly($parentAttribute->getParentAttributeDetailByKey('ApiName')) }}'
  description: '{{ $parentAttribute->getParentAttributeDetailByKey('HttpDescription') }}'
  request:
    columns:
@foreach($parentAttribute->getAttributesGroupByKeyName('Request') as $requestAttribute)
      - name: '{{ $requestAttribute->getAttributeDetailByKey('ColumnName') }}'
        description: '{{ $requestAttribute->getAttributeDetailByKey('ColumnDescription') }}'
        data_type: '{{ $requestAttribute->getAttributeDetailByKey('DataType') }}'
        default_value: '{{ $requestAttribute->getAttributeDetailByKey('DefaultValue') }}'
        rules: '{{ $requestAttribute->getAttributeDetailByKey('RequestRule') }}'
        messages: {!! $requestAttribute->ruleMessage() !!}
@endforeach
  response:
    columns:
@foreach($parentAttribute->getAttributesGroupByKeyName('Response') as $responseAttribute)
      - name: '{{ $responseAttribute->getAttributeDetailByKey('ColumnName') }}'
        description: '{{ $responseAttribute->getAttributeDetailByKey('ColumnDescription') }}'
        data_type: '{{ $responseAttribute->getAttributeDetailByKey('DataType') }}'
@endforeach
```
----
[Otherパターン](https://docs.google.com/spreadsheets/d/1vvc4X7OoDwMXQyngXLoVQMwxnyALDxnyvKTjCqgKT7M/edit#gid=0)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1490767/8399b989-d37e-b1b9-65cd-12d0c0808c9a.png)

```yaml
// $parentAttribute->getAttributesGroupByKeyName('*')には子側のデータの配列が格納されています
- names:
@foreach($parentAttribute->getAttributesGroupByKeyName('*') as $attribute)
    - id: '{{ $attribute->getAttributeDetailByKey('id') }}'
      name: '{{ $attribute->getAttributeDetailByKey('name') }}'
      name_detail: '{{ $attribute->getAttributeDetailByKey('name_detail') }}'
@endforeach
```

## Yamlファイルの出力コマンド
```bash
php artisan spread_sheet_converter:create_definition_document
```

## 関連
https://qiita.com/nagareboshi/items/8369b554d07b27760e59

https://qiita.com/nagareboshi/items/66aaadf495911493e854