0
0

More than 3 years have passed since last update.

Laravelを知らない中級(中年)プログラマーがマイグレーションファイルの仕組みを調べてみたけど全くわからない!その7「スキーマビルダー」

Last updated at Posted at 2020-04-24

INDEX

Laravelを知らない中級(中年)プログラマーがマイグレーションファイルの仕組みを調べてみたけど全くわからない!

スキーマビルダー

前回はデータベース接続について読みました。
Schema::getFacadeAccessor()static::$app['db']->connection()の戻り値が接続を確立したConnectionインスタンスであるというところまでは読みました。続きを見てみましょう。

Illuminate/Support/Facades/Schema::getFacadeAccessor()
    /**
     * Get a schema builder instance for a connection.
     *
     * @param  string|null  $name
     * @return \Illuminate\Database\Schema\Builder
     */
    public static function connection($name)
    {
        return static::$app['db']->connection($name)->getSchemaBuilder();
    }

Connection::getSchemaBuilder()メソッドを見てみましょう。

Connection::getSchemaBuilder()|関連メソッド
    /**
     * Get a schema builder instance for the connection.
     *
     * @return \Illuminate\Database\Schema\Builder
     */
    public function getSchemaBuilder()
    {
        if (is_null($this->schemaGrammar)) {
            $this->useDefaultSchemaGrammar();
        }
        return new SchemaBuilder($this);
    }
    /**
     * Set the schema grammar to the default implementation.
     *
     * @return void
     */
    public function useDefaultSchemaGrammar()
    {
        $this->schemaGrammar = $this->getDefaultSchemaGrammar();
    }
    /**
     * Get the default schema grammar instance.
     *
     * @return \Illuminate\Database\Schema\Grammars\Grammar
     */
    protected function getDefaultSchemaGrammar()
    {
        //
    }

Connection::getSchemaBuilder()

引数はありません。
戻り値はBuilderインスタンスです。

$this->schemaGrammarnullの場合、useDefaultSchemaGrammar()をコールします。その先ではgetDefaultSchemaGrammar()メソッドがコールされていますが、ロジックは空です。オーバーロードして使うのでしょうか。ちょっと意図がわかりません。
その後にSchemaBuilderを引数に自身を渡して生成します。SchemaBuilderIlluminate\Database\Schema\Builderが実体です。見てみましょう。

Builder::__construct()
    /**
     * Create a new database Schema manager.
     *
     * @param  \Illuminate\Database\Connection  $connection
     * @return void
     */
    public function __construct(Connection $connection)
    {
        $this->connection = $connection;
        $this->grammar = $connection->getSchemaGrammar();
    }
Connection::getSchemaGrammar()
    /**
     * Get the schema grammar used by the connection.
     *
     * @return \Illuminate\Database\Schema\Grammars\Grammar
     */
    public function getSchemaGrammar()
    {
        return $this->schemaGrammar;
    }
    /**
     * Set the schema grammar used by the connection.
     *
     * @param  \Illuminate\Database\Schema\Grammars\Grammar  $grammar
     * @return $this
     */
    public function setSchemaGrammar(Schema\Grammars\Grammar $grammar)
    {
        $this->schemaGrammar = $grammar;
        return $this;
    }

Builder::__construct()

第一引数はConnectionインスタンスです。
戻り値はありません。

Connectionインスタンスを受け取り、$this->connectionに代入します。
受け取ったConnectiongetSchemaGrammar()メソッドの返り値を$this->grammarに代入しています。ただ、先程Connection::getSchemaBuilder()を読んだ時に、$schemaGrammarは設定されていませんでした。Builderクラスには$grammarを変更するインターフェースがコンストラクタ以外に見当たりません。Connection::setSchemaGrammar()メソッドが用意されているので、何かのタイミングでConnectionインスタンスにセットした後にBuilderインスタンスを生成するのかもしれません。とりあえず保留して読みすすめましょう。

Illuminate/Support/Facades/Facade::__callStatic()
    /**
     * Handle dynamic, static calls to the object.
     *
     * @param  string  $method
     * @param  array  $args
     * @return mixed
     *
     * @throws \RuntimeException
     */
    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);
    }

Facade::__callStatic()

第一引数はストリング型でメソッド名です。
第二引数は配列型で引数をまとめたものです。
戻り値はmixです。

さて、Schema::getFacadeAccessor()の戻り値がBuilderインスタンスであるというところまで読めました。
この記事の冒頭で叩いたコマンド、

php artisan make:migration create_customers_table --create=customers

によって生成されたマイグレーションファイルのup()及びdown()メソッドに記述されているstaticメソッドSchema::create()等はSchemaクラスが継承している抽象クラスFacade__callStatic()がコールされ、その処理の中の$instance = static::getFacadeRoot()のステップで$instanceには今まで追ってきてたどり着いたBuilderインスタンス が代入されるはずです。

インスタンスの代入に失敗した場合、「A facade root has not been set.」というメッセージを添えて、例外RuntimeExceptionをスローします。
インスタンスが無事代入された場合は、引数として受け取ったメソッド名からコールするメソッドを割り出し、引数として受け取った引数配列を指定してコールします。最初に戻って生成されたマイグレーションファイルを見てみましょう。

生成されたファイル::up()
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

生成されたファイル::up()

引数、戻り値はありません。

つまり、Builder::create()メソッドを第一引数としてテーブル名のストリング、第二引数としてクロージャーを指定してコールするという設計だということがわかりました。
すばらしい!何をやっているのかちょっとわかってしまいましたね!
本日は少し短いですが、次回からだんだん区切りが長くなってきそうです。

次回

次は実際にマイグレーションが実行される流れを見てみましょう!
楽しみですね!

続く☆

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0