【Laravel】migrationで複数テーブルの共通カラム定義を1か所に共通化する方法

# はじめに
複数のテーブルに同じカラムを持たせるとき、
migrationでテーブル1つ1つに同じカラム定義を記述するのは面倒です。

例えば、よく使われるのは
created_at、created_by、updated_at、updated_by、deleted_at、deleted_byなどです。

普通にやると各テーブルごとに上記カラム定義を記述することになりますね。

```php
    public function up()
    {
        Schema::create('foo_table', function (Blueprint $table) {
            $table->id();

            $table->timestamp('created_at')->nullable();
            $table->unsignedBigInteger('created_by')->nullable();
            $table->timestamp('updated_at')->nullable();
            $table->unsignedBigInteger('updated_by')->nullable();
            $table->timestamp('deleted_at')->nullable();
            $table->unsignedBigInteger('deleted_by')->nullable();
        });

        Schema::create('bar_table', function (Blueprint $table) {
            $table->id();

            $table->timestamp('created_at')->nullable();
            $table->unsignedBigInteger('created_by')->nullable();
            $table->timestamp('updated_at')->nullable();
            $table->unsignedBigInteger('updated_by')->nullable();
            $table->timestamp('deleted_at')->nullable();
            $table->unsignedBigInteger('deleted_by')->nullable();
        });

        Schema::create('baz_table', function (Blueprint $table) {
            $table->id();

            $table->timestamp('created_at')->nullable();
            $table->unsignedBigInteger('created_by')->nullable();
            $table->timestamp('updated_at')->nullable();
            $table->unsignedBigInteger('updated_by')->nullable();
            $table->timestamp('deleted_at')->nullable();
            $table->unsignedBigInteger('deleted_by')->nullable();
        });
    }
```

※Laravelは`$table->timestamps();`という機能を提供しており、created_atとupdated_atだけは共通で定義可能です

このように全テーブルに毎回共通カラム定義を羅列するのは面倒です。
共通コード1か所だけにそのカラム定義を記述し、
migrationではそれを利用するだけの形が望ましいです。
こんなイメージ。

```php
    public function up()
    {
        Schema::create('foo_table', function (Blueprint $table) {
            $table->id();

            $table->systemColumns(); // 共通カラム定義
        });

        Schema::create('bar_table', function (Blueprint $table) {
            $table->id();

            $table->systemColumns(); // 共通カラム定義
        });

        Schema::create('baz_table', function (Blueprint $table) {
            $table->id();

            $table->systemColumns(); // 共通カラム定義
        });
    }
```

`$table->systemColumns();`を呼ぶだけで6つの共通カラムが定義できる状態です。


Laravelではmacroという機能を利用してBlueprintクラスを拡張することで
いい感じにできるので、今回はその方法を紹介します。

# macroとは
macroとは、Laravelフレームワーク自体が提供しているクラスに
好きなメソッドを追加することができる機能です。

例えば、
Requestクラスにユーザーエージェントを判定するメソッドを追加してみたり、
Carbonクラスに特定のフォーマットに変換するメソッドを追加してみたり、
Laravelのクラスに自由にメソッドを追加できます。

macroの詳しい使い方や
macro利用可能なクラスなどについては
[こちらの記事](https://public-constructor.com/laravel-add-method-to-collection-or-facade/)が非常にわかりやすく解説していますのでご参考に。

今回は、migrationで利用されている
Blueprintクラスにこのmacroで機能追加することによって
共通カラムのコード共通化を行います。

# Blueprintにmacro追加
まずはBlueprintのmacroを定義するために
サービスプロバイダを新しく作ります。

makeコマンド実行。

```shell
php artisan make:provider BlueprintServiceProvider
```

すると下記のようにBlueprintServiceProviderのクラスが生成されます。

```app/Providers/BlueprintServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\ServiceProvider;

class BlueprintServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

```

このbootメソッドに、macro定義を記述します。

```app/Providers/BlueprintServiceProvider.php
    public function boot()
    {
        Blueprint::macro('systemColumns', function () {
            $this->timestamp('created_at')->nullable();
            $this->unsignedBigInteger('created_by')->nullable();
            $this->timestamp('updated_at')->nullable();
            $this->unsignedBigInteger('updated_by')->nullable();
            $this->timestamp('deleted_at')->nullable();
            $this->unsignedBigInteger('deleted_by')->nullable();
        });
    }
```

これでBlueprintクラスに`systemColumns`というメソッドが追加されました。

このサービスプロバイダを有効にするため、
`config/app.php`に登録します。

```config/app.php
'providers' => [
    // 中略
    App\Providers\BlueprintServiceProvider::class,
];
```

これでBulueprintへのmacro定義完了です。

# migrationでmacroを利用
あとは、冒頭で見せたように、
migrationでこのmacroを呼び出すだけです。

```php
    public function up()
    {
        Schema::create('foo_table', function (Blueprint $table) {
            $table->id();

            $table->systemColumns(); // 共通カラム定義
        });

        Schema::create('bar_table', function (Blueprint $table) {
            $table->id();

            $table->systemColumns(); // 共通カラム定義
        });

        Schema::create('baz_table', function (Blueprint $table) {
            $table->id();

            $table->systemColumns(); // 共通カラム定義
        });
    }
```

migrationでは`$table->systemColumns();`と書いているだけですが、
内部的には先ほど定義したmacroの`systemColumns`メソッドが呼び出されていて
created_at、created_by、updated_at、updated_by、deleted_at、deleted_by
の6つのカラムを定義してくれています。

# 参考
https://public-constructor.com/laravel-add-method-to-collection-or-facade/