Laravel × Docker AlpineでER図を自動生成する

こんにちは。むらってぃーです。
[Laravel Advent Calendar 2020](https://qiita.com/advent-calendar/2020/laravel)の3日目を担当させていただきます。

皆さんはER図使っていますか？
エンティティ同士の関係が一目でわかるドキュメントであるため、手元にあれば非常に便利なものとして効力を発揮します。
一方で、DBスキーマを更新するたびにER図を書き換える必要があり、メンテナンスコストが少々高めです。

今回はLaravelでアプリケーションを開発する際、Eloquent ModelからER図を自動生成するツールを紹介します。
DockerのAlpineイメージでLaravelを動かし、その上で生成します。
そのため、チームで運用する際にも導入しやすいです。

なお、今回生成するER図はこちらです。
![スクリーンショット 2020-11-22 15.56.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/3e02b5b5-100f-6f76-ca21-03b85281281c.png)

## Laravel ER Diagram Generator
https://github.com/beyondcode/laravel-er-diagram-generator

LaravelのEloquentModelから、ER図を自動生成するライブラリです。
Star数は1000超えで、多くの方に利用されているみたいです。

## インストール
### Dockerfile
Laravelを動かしているAlpineイメージに下記を追加します。
内部でgraphvizというツールを使っているため、apk経由でそちらをインストールします。
フォントもインストールしないと、ER図に日本語や英語が出力されないので入れておきます。

```Dockerfile
RUN apk --no-cache add graphviz fontconfig \
    && rm -rf /var/cache/apk/* \
    # graphviz用フォントインストール
    && curl -O https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip \
    && mkdir -p /usr/share/fonts/NotoSansCJKjp \
    && unzip NotoSansCJKjp-hinted.zip -d /usr/share/fonts/NotoSansCJKjp/ \
    && rm NotoSansCJKjp-hinted.zip \
    && fc-cache -fv
```

### composer.json
Alpineイメージに入り込み、下記コマンドでLaravel ER Diagram Generatorを入れます。

```
composer require beyondcode/laravel-er-diagram-generator --dev
```

### ServiceProvider
ローカルでのみこのライブラリが読み込まれるようにします。

```AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        if ($this->app->environment('local')) {
            // ER図生成用のProviderはcomposer の require-devでインストールしているので、localでのみ使用
            $this->app->register(\BeyondCode\ErdGenerator\ErdGeneratorServiceProvider::class);
        }
    }
    ...
```

### config用意・修正
下記コマンドで、configファイルをライブラリ内からプロジェクト内にコピー。

```
cp ./vendor/beyondcode/laravel-er-diagram-generator/config/config.php config/erd-generator.php
```

今回は App/Models配下にモデルファイルを置くため、configでModelファイルの読み込み先を下記に変更します。

```config/erd-generator.php
<?php

return [

    /*
     * All models in these directories will be scanned for ER diagram generation.
     * By default, the `app` directory will be scanned recursively for models.
     */
    'directories' => [
        base_path('app') . '/Models',
    ],
...
```

## Model用意
では、Modelを用意します。

### Model概要
今回は下記のモデルにしてみます。

#### Book(本)
| カラム名 | 備考 |
|---|---|
|ID|自動採番ID|
|Title|タイトル|
|AuthorID|著者ID. 著者テーブルへのリレーション.|

#### Author(著者)
| カラム名 |備考|
|---|---|
|ID|自動採番ID|
|Name|著者名|

### マイグレーションファイル用意

authorsテーブルとbooksテーブルを作ります。

```2020_11_09_154434_create_tables.php
...
class CreateTables extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('authors', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('name');
            $table->timestamps();
        });

        Schema::create('books', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->integer('author_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('books');
        Schema::dropIfExists('authors');
    }
}
```

こちらはそのまま流します。

```
php artisan migrate
```

### Modelファイル用意
```app/Models/Author.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Author extends Model
{
}
```

```app/Models/Book.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Book extends Model
{
    public function author(): BelongsTo
    {
        return $this->belongsTo('App\Models\Author');
    }
}
```

Bookには、Authorへのリレーションを記載します。

なお、ER図に記載されるその他のフィールドは、アプリケーションが繋がっているDBから読み取ってくれる動きです。

## ER図生成
Alpineコンテナの中に入り、下記のコマンドを打ちます。

```
php artisan generate:erd er-diagram.png
```

すると、プロジェクトルートに er-diagram.pngというファイルが出来上がります。

![スクリーンショット 2020-11-22 15.56.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/3e02b5b5-100f-6f76-ca21-03b85281281c.png)

Userは、Laravelで最初から組み込まれているものです。
このようにBookとAuthorの関係がER図として出力されています。

BelongsToの矢印が色付けされているのが個人的には嬉しいです。

## 最後に
今回はLaravel ER Diagram Generatorを使い、Larvel × Docker AlpineでER図を自動生成する方法を紹介しました。
一度このように土台を作れば、migrationファイルとModelファイルの管理のみでER図を自動生成できます。
メンテナンスコストがほとんどかからないのが嬉しいですね。
ER図生成のコマンドはCIに組み込むなりして、常に最新に保つことができればさらに幸せになれそうですね！