Laravel入門者が マイグレーション処理の流れを クソ丁寧に追ったら、追いきれなくなった話

# 結論から申し上げます

本記事はなにもまとまっておらず、**ただただmigrationに係るファイルを一つ一つ追っていったログ** です。

本当は↓↓こんな感じの図を交えつつ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/241647/0c2cb9f6-8af9-b991-846c-ffe1d3905970.png)


「Laravelのmigration処理を解き明かしたった！」みたいなタイトルで一世を風靡しようと思ったのですが、**挫折しました。**

せっかく途中まで調べたので恥を忍んで公開しておこうと思います。
悔しいからまた挑戦します！！

ということで、以下ログです。

# migrationってなに？

まずはmigrationの本来の意味を調べます。

> mi·gra·tion
1. seasonal movement of animals from one region to another.
2. movement from one part of something to another.

ざっくり**"場所から場所への移動"**と捉えておけば問題ないでしょう。

次に、公式ドキュメントを確認。
https://readouble.com/laravel/5.5/ja/migrations.html

...横文字だらけでわかりづらいのですが、要するに**データベースの定義をLaravelからできるもの**です。

1. Migrationファイルを作って
2. そのファイルの中身に指令を書き込んで
3. その指令通りにLaravelにデータベースを操作してもらう

この３パターンで完了です！

ということで、それぞれの処理について詳細をみていきましょう。

# 登場人物
開発者とLaravel、そしてデータベースです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/241647/914acb27-68f7-5ee6-ecc8-66a67497db06.png)


# migrationファイルを作る

まずは、マイグレーション処理をするために、migrationファイルを作成しましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/241647/f8b36790-3e18-2ab0-113b-e83d206ffd74.png)

マイグレーションファイルを作るためには、`php artisan`コマンドを使います。Laravel用のコマンドですね。
（artisanは職人という意味らしいです）

ここでは、`test`というテーブルを作成したいとします。

```bash
root@8c8e2d4a121f:/var/www# php artisan make:migration create_tests_table
Created Migration: 2019_03_01_085359_create_tests_table
```

すると、database/migrations 配下に新しいファイルができているのがわかります。

![](https://d2mxuefqeaa7sj.cloudfront.net/s_EC63D1AC9DFA0DB2EF66D6CC1410C68A09547F72673BE2C3B24A7711868FA35A_1551430609481_image.png)

ファイルの中身をみてみましょう。

```php:2019_03_01_085359_create_tests_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTestsTable extends Migration
{
    public function up()
    {
        Schema::create('tests', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('tests');
    }
}
```

`Migration`クラスを継承する形で`CreateTestsTable`クラスが作成されていることがわかると思います。

中身をみてみると、`up()`という関数と`down()`という関数があることがわかります。

`up()`メソッドは新規テーブル、カラム、インデックスをデータベースに追加することができます。`down()`は逆に、`up()`メソッドの処理を元に戻す機能を記述します。

そして、両メソッド - `up()`と`down()` - の中身は`Schema`ファサードが使えます。Schemaとは何か。それを次にみていきます。


## 回り道： Migration.phpを覗いてみる
では、少し回り道をして`Migration`クラスを覗いてみましょう。

抽象クラスのようですね。
コメントを日本語化して掲載してみます。

※抽象クラスの解説はこちらの記事が詳しいです。
https://laraweb.net/surrounding/1972/

```php
<?php

namespace Illuminate\Database\Migrations;

abstract class Migration
{
    //データベース接続するために使う名前。
    protected $connection;

    //サポートされている場合、トランザクション内でマイグレーションをラップすることを可能にします。
    public $withinTransaction = true;

    //マイグレーション接続の名前を取得します。
    public function getConnection()
    {
        return $this->connection;
    }
}
```

Migrationクラス自体は抽象メソッド(abstract)ですが、内部のメソッド・プロパティには`abstract`が定義されていないので、これら３つはそのまま`CreateTestsTable`クラスに継承されるわけですね。

# up()の中身を記述する - Schemaファサード

さて、では`up()`メソッドの中身を改めて確認していきましょう。

```php:2019_03_01_085359_create_tests_table.php
public function up()
{
    Schema::create('tests', function (Blueprint $table) {
        $table->increments('id');
        $table->timestamps();
    });
}
```

ファサードってなんぞ？となると思いますが、ここでファサードの元々の意味をまた確認してみましょう。

>fa·cade
the face of a building, especially the principal front that looks onto a street or open space.

建物の正面、という意味です。詳細はこちらの記事がわかりやすかったです。

https://qiita.com/yousan/items/18dab4dbac4a27ce3662

>Laravelのファサードとは、建築用語での「建築物 の 正面部分」という意味が、プログラミングでの「ライブラリ（建築物）の呼び出し部分（正面部分）」という意味になるわけですね。

ということで、Schemaファサード（ここでは`create`）についてみていきましょう

```php
Schema::create('tests', function (Blueprint $table) {
    $table->increments('id');
    $table->timestamps();
});
```

`::`はスコープ定義演算子です。**クラスをインスタンス化しなくても、クラス内のプロパティを扱うことができます**。
http://php.net/manual/ja/language.oop5.paamayim-nekudotayim.php

つまり、Schemaのcreateメソッドを実行して、という意味でそのまんま捉えてOKです。

```php
Schema::create([テーブル名], [Blueprintオブジェクトを受け取るクロージャ関数] )
```

という形式で書かれています。

## 回り道：createを探す旅

さて、ここでまた回り道をしてcreateがどこに記述されているかを確認してみましょう。

Schemaクラスを確認してみます。

vendor/laravel/framework/src/Illuminate/Support/Facades/Schema.php

```php:Schema.php

<?php

namespace Illuminate\Support\Facades;

/**
 * @method static \Illuminate\Database\Schema\Builder create(string $table, \Closure $callback)
 * ...
 * @see \Illuminate\Database\Schema\Builder
 */
class Schema extends Facade
{
    /**
     * 接続のために Schema Builder インスタンスを取得する。
     * @return \Illuminate\Database\Schema\Builder
     */
    public static function connection($name)
    {
        return static::$app['db']->connection($name)->getSchemaBuilder();
    }

    /**
     * Schema Builder インスタンスを デフォルトの接続として取得する。
     * @return \Illuminate\Database\Schema\Builder
     */
    protected static function getFacadeAccessor()
    {
        return static::$app['db']->connection()->getSchemaBuilder();
    }
}

```

...あれ？createがない？
ということで、継承元の`Facade`クラスを確認してみるが、ない。


あちこち探してみると、こんな場所にいました。

vendor/laravel/framework/src/Illuminate/Database/Schema/Builder.php

```php:Builder.php
<?php

namespace Illuminate\Database\Schema;

use Closure;
use LogicException;
use Illuminate\Database\Connection;

class Builder
{
    ...
    /**
     * schema上にテーブルを作成する。
     */
    public function create($table, Closure $callback)
    {
        $this->build(tap($this->createBlueprint($table), function ($blueprint) use ($callback) {
            $blueprint->create();

            $callback($blueprint);
        }));
    }
    ...
}

```

`create($table, Closure $callback)`となっており、先ほどの定義と一致しますね。

でも`Builder`クラスなんて`Schema`クラスにはどこにも出てきません。
では、どこで接続するのか？


...それは、後半のお楽しみ。


閑話休題。
`Facade`クラスにも`connection()`メソッドはありませんでした。
するとどういうことが起こるのか？

`Facade`クラス内の`__callStatic`に注目してください。

vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php

```php:Facade.php

<?php

namespace Illuminate\Support\Facades;
...

abstract class Facade
{
    ...
    
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        return $instance->$method(...$args);
    }
}
```

`__callStatic`は**マジックメソッド**と呼ばれるPHPの文法の一種で、アンダーライン２つ(__)から始まる関数名は、ある条件下の時に発動するメソッドです。
http://php.net/manual/ja/language.oop5.magic.php


`__callStatic`は存在しない静的メソッドが呼ばれたら実行されます。

ここで振り返ってみてください。

`Schema::create`と`create`メソッドを呼び出しているのに、`Schema`クラスにも、`Facade`クラスにも`create`が存在しません。
...そう、つまり、`__callStatic`が実行されるわけです！

ということで、`__callStatic`の中身を見ましょう。

すると、

```php
$instance = static::getFacadeRoot();
```

という処理を行なっていますね。

ちなみにここで`static::`が使用されていますが、これは**遅延静的束縛**と呼ばれるものです。
ここでは説明を割愛しますが、こちらのサイトがわかりやすいです。
https://ackintosh.github.io/blog/2013/08/25/late-static-binding/

では、`getFacadeRoot`に関連する場所を探してみましょう。

```php:Facade.php

    /**
     * ファサードの裏にあるルートオブジェクトを取得する
     */
    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }

    /**
     * ファサードのルートのインスタンスをコンテナから解決する
     */
    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        return static::$resolvedInstance[$name] = static::$app[$name];
    }

```

まずは`static::resolveFacadeInstance(static::getFacadeAccessor())`という処理をさせたいわけですね。
ここで着目したいのが`getFacadeAccessor()`はどこにあるのか、という話。
これは、はるか昔に書いた、`Scheme`クラスの中に出てきます。

```php:Schema.php

<?php

namespace Illuminate\Support\Facades;

class Schema extends Facade
{
    protected static function getFacadeAccessor()
    {
        return static::$app['db']->connection()->getSchemaBuilder();
    }
}

```

`$app`はFacade側で定義されています(ややこしい...)
再び戻って確認します。
すると、こんな関数が。

```php:Facade.php

    public static function setFacadeApplication($app)
    {
        static::$app = $app;
    }

```

どうやら、bootstrap中にこの`setFacadeApplication`メソッドを使って値を設定するようです。

https://daylerees.com/laravel-facades/
>The first static property contains a reference to the Laravel IoC container. It’s set during the framework bootstrap process using the setFacadeApplication() method found in the full example above. 

で、このプロパティはabstract facadeにくっついているから、`Facade`クラスを継承する全てのクラスに適用されるらしい。なるほど。

ということで、コメント部にあるように、

```php:Facade.php
    /**
     * The application instance being facaded.
     *
     * @var \Illuminate\Contracts\Foundation\Application
     */
    protected static $app;
```

という定義で良いようだ。
Illuminate\Contracts\Foundation には `Application.php`がある。
そして、これがサービスコンテナの操作をすることができるインスタンスなのだ。
やっとゴールが見えてきた気がするぞ！！


さて、ここで更に寄り道。

```php
        return static::$app['db']->connection()->getSchemaBuilder();
```

これ、なんで配列になっているか、気になりませんか？
クッソ調べまくって見つけました。
https://stackoverflow.com/questions/50530710/how-laravel-uses-object-as-an-array-in-facade-class?rq=1

PHPにある`ArrayAccess`インターフェイスを使っているからでした。
http://php.net/manual/ja/class.arrayaccess.php
スッキリした...！

なので、
`$app['db']`インスタンスを参照ているわけです。

つまり、下記とニアリーイコールです。
`DB`ファサードは `Illuminate\Database\DatabaseManager` を参照します。

ここのファサードクラス一覧に書いてあります。
https://readouble.com/laravel/5.5/ja/facades.html

ということで、当該の`DatabaseManager.php`をみてみましょう

```php:DatabaseManager.php
<?php

namespace Illuminate\Database;

use PDO;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Illuminate\Database\Connectors\ConnectionFactory;

/**
 * @mixin \Illuminate\Database\Connection
 */
class DatabaseManager implements ConnectionResolverInterface
{
    ...

    /**
     * The application instance.
     *
     * @var \Illuminate\Foundation\Application
     */
    protected $app;

    ...

    /**
     * 新規の DataBaaseManagerインスタンスを作成する
     * @param  \Illuminate\Foundation\Application  $app
     * @param  \Illuminate\Database\Connectors\ConnectionFactory  $factory
     * @return void
     */
    public function __construct($app, ConnectionFactory $factory)
    {
        $this->app = $app;
        $this->factory = $factory;
    }

    ...

    /**
     * Database Connection インスタンス を取得する。
     * @param  string  $name
     * @return \Illuminate\Database\Connection
     */
    public function connection($name = null)
    {
        list($database, $type) = $this->parseConnectionName($name);

        $name = $name ?: $database;

        // If we haven't created this connection, we'll create it based on the config
        // provided in the application. Once we've created the connections we will
        // set the "fetch mode" for PDO which determines the query return types.
        if (! isset($this->connections[$name])) {
            $this->connections[$name] = $this->configure(
                $this->makeConnection($database), $type
            );
        }

        return $this->connections[$name];
    }
    
    ...

}
```

先ほど言ったように、`DB`ファサードはインスタンス化されているため、`__construct`メソッドは実行ずみです。

では、`connection()`メソッドの内部を深掘りしていきましょう。
すると、PHP弱者には初めましての文法がたくさん...

確認していきます。

```
list($database, $type) = $this->parseConnectionName($name);
```


これは、List関数です。右辺の配列を順に左側の変数に代入してくれます。
http://php.net/manual/ja/function.list.php

https://www.sejuku.net/blog/24406
こちらの例がわかりやすいですね。引用します。

```php
$fruits_array = ['りんご', 'オレンジ', 'メロン'];
 
//listの複数変数を配列から代入
list($apple, $orange, $melon) = $fruits_array;
```

今回の例では、`parseConnectionName($name)`で取得した配列の結果を順に代入している、ということのようですね。
parseってことはもともと繋がって入力されたものを分割するんでしょうね。
`$name`は今回入力がないため、connectionメソッドのargsデフォルト値である`$name = null`が適用されます。

```php:DatabaseManager.php

    protected function parseConnectionName($name)
    {
        $name = $name ?: $this->getDefaultConnection();

        return Str::endsWith($name, ['::read', '::write'])
                            ? explode('::', $name, 2) : [$name, null];
    }

```

出たな、三項演算子！

`?:`と書かれると「ん？」となりますが、怖がることはありません。

```php
$name = $name ?: $this->getDefaultConnection();
```

は

```php
$name = $name ? $name : $this->getDefaultConnection();
```

と同義です。

もっというと、

```php
if ( $name ) {
    $name = $name;
} else {
    $name = $this->getDefaultConnection();
}
```

です。
ということで、今回は前述のように`$name`は`null`なので、`getDefaultConnection()`メソッドが発動します。


```php:DatabaseManager.php

    public function getDefaultConnection()
    {
        return $this->app['config']['database.default'];
    }

```

appは$appが代入されている箇所があります。つまり、先ほどと同じ、`\Illuminate\Foundation\Application`のインスタンスです。

では、`$this->app['config']['database.default']`とはなんでしょうか。

またこちらをreferします。
https://readouble.com/laravel/5.5/ja/facades.html

`Config` は `Illuminate\Config\Repository` らしい。
というところまではわかったのですが、どこの値を参照しているかまでは追えず....
StackOverflowにも投げてみようかと思いまうす。
わかるかた、コメントいただけると嬉しいです。

一度立ち戻って、`parseConnectionName($name)`はコメント通り

> Parse the connection into an array of the name and read / write type.

つまり、名前と読み書き権限の配列を返してくれるメソッドだと理解して次に進みましょう。

随分上になってしまったので`connection()`メソッドを再掲します。

```php:connection()

    /**
     * Database Connection インスタンス を取得する。
     * @param  string  $name
     * @return \Illuminate\Database\Connection
     */ 
    public function connection($name = null)
    {
        list($database, $type) = $this->parseConnectionName($name);

        $name = $name ?: $database;

        // If we haven't created this connection, we'll create it based on the config
        // provided in the application. Once we've created the connections we will
        // set the "fetch mode" for PDO which determines the query return types.
        if (! isset($this->connections[$name])) {
            $this->connections[$name] = $this->configure(
                $this->makeConnection($database), $type
            );
        }

        return $this->connections[$name];
    }

```

`parseConnectionName($name)`のおかげで、`名前`と`読み書き権限`を`$database`と`$type`に格納することができました。
そして、もし`connections[$name]`が存在しなかったら、`configure()`メソッドを実行して、設定をしてくれます。

```php:DatabaseManager.php
    /**
     * DatabaseConnectionインスタンスを準備する
     *
     * @param  \Illuminate\Database\Connection  $connection
     * @param  string  $type
     * @return \Illuminate\Database\Connection
     */
    protected function configure(Connection $connection, $type)
    {
        $connection = $this->setPdoForType($connection, $type);

        // First we'll set the fetch mode and a few other dependencies of the database
        // connection. This method basically just configures and prepares it to get
        // used by the application. Once we're finished we'll return it back out.
        if ($this->app->bound('events')) {
            $connection->setEventDispatcher($this->app['events']);
        }

        // Here we'll set a reconnector callback. This reconnector can be any callable
        // so we will set a Closure to reconnect from this manager with the name of
        // the connection, which will allow us to reconnect from the connections.
        $connection->setReconnector(function ($connection) {
            $this->reconnect($connection->getName());
        });

        return $connection;
    }
```

そして、注目して欲しいのが戻り値の型。

```
@return \Illuminate\Database\Connection
```

となっていますね。

`Connection`クラスを確認してみましょう。

vendor/laravel/framework/src/Illuminate/Database/Schema/Connection.php

```php:Connection.php
<?php

namespace Illuminate\Database;
...
use Illuminate\Database\Schema\Builder as SchemaBuilder;
...
class Connection implements ConnectionInterface
{
    ....
    /**
     * 接続のために SchemaBuilderインスタンスを作成する
     *
     * @return \Illuminate\Database\Schema\Builder
     */
    public function getSchemaBuilder()
    {
        if (is_null($this->schemaGrammar)) {
            $this->useDefaultSchemaGrammar();
        }

        return new SchemaBuilder($this);
    }
    ...
}

```

なんか見覚えのある奴がいませんか？

...そう、'Builder'クラスだ！

覚えていない人のためにもう一度。`create()`メソッドがいる場所でしたね。

vendor/laravel/framework/src/Illuminate/Database/Schema/Builder.php

```php:Builder.php
<?php

namespace Illuminate\Database\Schema;

use Closure;
use LogicException;
use Illuminate\Database\Connection;

class Builder
{
    ...
    /**
     * schema上にテーブルを作成する。
     */
    public function create($table, Closure $callback)
    {
        $this->build(tap($this->createBlueprint($table), function ($blueprint) use ($callback) {
            $blueprint->create();

            $callback($blueprint);
        }));
    }
    ...
}

```

この`Builder`クラスが`Connection`クラスで`use Illuminate\Database\Schema\Builder as SchemaBuilder;`として呼び出されています。つまり、`SchemaBuilder`として先ほどの`Builder`クラスが使われているわけですね。
そして、`getSchemaBuilder()`というメソッドでSchemaBuilder, すなわち `Builder`クラスのインスタンスを作成しているんですね！
(ちなみに名前をわざわざ`SchemaBuilder`としているのは、 ...\ **Query** \Builder もuseしているためです。こちらを`QueryBuilder`として名前を分けています。）

```php
SchemaBuilder($this)
```

`$this`とは、`Connection`クラス自身を指します。

では、改めてSchema/Builder.phpの`__constructor`(クラスがインスタンス化された時に呼び出されるメソッド)を確認しましょう。

```php:Builder.php
    public function __construct(Connection $connection)
    {
        $this->connection = $connection;
        $this->grammar = $connection->getSchemaGrammar();
    }
```

ここで注目するのは`getSchemaGrammer()`です。Builderをインスタンス化するときに、Schemaの文法を取得しろ、と命令しているわけです。
怪しくなってきましたね。

ということで、再び`Connection`クラスに戻り、`getSchemaGrammer()`を確認します。

```php:Connection.php
    public function getSchemaGrammar()
    {
        return $this->schemaGrammar;
    }
```
このschemaGrammerは `setSchemaGrammar()`によって定義されます。

```php:Connection.php
    public function setSchemaGrammar(Schema\Grammars\Grammar $grammar)
    {
        $this->schemaGrammar = $grammar;
    }
```

---

...頭がごっちゃごちゃになったので一旦ここまでで勘弁してください....


# 参考
[How Laravel Facades Work and How to Use Them Elsewhere](https://www.sitepoint.com/how-laravel-facades-work-and-how-to-use-them-elsewhere/)
ファサードの概念を掴むのにめっちゃわかりやすい
[Laravel Facades](https://phpnews.io/feeditem/laravel-facades)
これもファサードの解説
<a target="_blank" href="https://www.amazon.co.jp/gp/product/4802611846/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4802611846&linkCode=as2&tag=cha1ra-22&linkId=808ceacf3ce13140cb5ae86dd8640c71">PHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応</a>
サービスコンテナの概要はこの本。