Laravelを知らない中級（中年）プログラマーがマイグレーションファイルの仕組みを調べてみたけど全くわからない！その３「Repositoryクラス」


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

- [その１「マイグレーションファイルを見てみよう」](https://qiita.com/xioncc/items/1dcec2fbe3485b7e769a)
- [その２「$app['db']って何者？」](https://qiita.com/xioncc/items/cd4a46e5aca16b13174d)
- [その３「Repositoryクラス」](https://qiita.com/xioncc/items/1ce2132594c4596a73ae)
- [その４「Larabelアプリケーションの初期化の流れ」](https://qiita.com/xioncc/items/a17d7f905d4a5abf8103)
- [その５「リポジトリの読込」](https://qiita.com/xioncc/items/dc7df63c2487b02052f3)
- [その６「データベース接続」](https://qiita.com/xioncc/items/3cf9336eecd5f6905831)
- [その７「スキーマビルダー」](https://qiita.com/xioncc/items/04c95ce9ff6d0b7c9d44)
- [その８「migrate コマンドの実行」](https://qiita.com/xioncc/items/4a5166a0963991e33eb5)


## Repositoryクラス
前回``DatabaseManager``の``$this->app['config']['database.default']``ってなんだろうというところまで読みました。それを追ってみましょう。
``DatabaseManager``クラスのコンストラクタは以下のように定義されています。

```php:Illuminate/Database/DatabaseManager&#x3a;&#x3a;__construct
    /**
     * Create a new database manager instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @param  \Illuminate\Database\Connectors\ConnectionFactory  $factory
     * @return void
     */
    public function __construct($app, ConnectionFactory $factory)
    {
        $this->app = $app;
        $this->factory = $factory;

        $this->reconnector = function ($connection) {
            $this->reconnect($connection->getName());
        };
    }
```

``$this->app``には生成される時の第一引数が代入されています。コードヒントには``Illuminate\Contracts\Foundation\Application``とあります。生成する時の手順はまだはっきりとわかりませんが、``$this->app``が``Application``インスタンスなのは確かなようです。
前回のコードリーディングで``Application``クラスは``Container``クラスを継承していて、``ArrayAccess``インターフェースを実装してることがわかっています。配列としてアクセスすると名前解決され指定されたクラスのインスタンスが渡されます。
エイリアス設定を参照すると、実体は ``Illuminate\Contracts\Config\Repository`` インターフェースを実装した ``Illuminate\Config\Repository`` だということがわかります。見てみましょう!

```php:Illuminate/Config/Repository抜粋
<?php
namespace Illuminate\Config;
use ArrayAccess;
use Illuminate\Contracts\Config\Repository as ConfigContract;
use Illuminate\Support\Arr;
class Repository implements ArrayAccess, ConfigContract
{
/**
 * All of the configuration items.
 *
 * @var array
 */
protected $items = [];
/**
 * Create a new configuration repository.
 *
 * @param  array  $items
 * @return void
 */
public function __construct(array $items = [])
{
    $this->items = $items;
}
/* ========== 中略 ========== */
/**
 * Get the specified configuration value.
 *
 * @param  array|string  $key
 * @param  mixed  $default
 * @return mixed
 */
public function get($key, $default = null)
{
    if (is_array($key)) {
        return $this->getMany($key);
    }
    return Arr::get($this->items, $key, $default);
}
/* ========== 中略 ========== */
/**
 * Get a configuration option.
 *
 * @param  string  $key
 * @return mixed
 */
public function offsetGet($key)
{
        return $this->get($key);
}
/* ========== 中略 ========== */
}
```

このクラスも``ArrayAccess``が実装されています。``offsetGet()``メソッドは``return $this->get($key)``と定義されています。配列で渡された時の処理を挟んでいますが、実行するのは``return Arr::get($this->items, $key, $default)``のようです。``Arr``クラスを見てみましょう。

## Arr::get
``Arr``クラスの定義ファイルは``Illuminate/Support/Arr.php``です。``get()``メソッドは以下のように定義されています。

```php:Illuminate/Support/Arr&#x3a;&#x3a;get()|accessible()
/**
 * Get an item from an array using "dot" notation.
 *
 * @param  \ArrayAccess|array  $array
 * @param  string|int|null  $key
 * @param  mixed  $default
 * @return mixed
 */
public static function get($array, $key, $default = null)
{
    if (! static::accessible($array)) {
        return value($default);
    }
    if (is_null($key)) {
        return $array;
    }
    if (static::exists($array, $key)) {
        return $array[$key];
    }
    if (strpos($key, '.') === false) {
        return $array[$key] ?? value($default);
    }
    foreach (explode('.', $key) as $segment) {
        if (static::accessible($array) && static::exists($array, $segment)) {
            $array = $array[$segment];
        } else {
            return value($default);
        }
    }
    return $array;
}
/**
 * Determine whether the given value is array accessible.
 *
 * @param  mixed  $value
 * @return bool
 */
public static function accessible($value)
{
    return is_array($value) || $value instanceof ArrayAccess;
}
/**
 * Determine if the given key exists in the provided array.
 *
 * @param  \ArrayAccess|array  $array
 * @param  string|int  $key
 * @return bool
 */
public static function exists($array, $key)
{
    if ($array instanceof ArrayAccess) {
        return $array->offsetExists($key);
    }

    return array_key_exists($key, $array);
}
```

説明の通り、「**ドット**」表記を使用して配列から値を取得するメソッドのようです。第一引数に``ArrayAccess``か配列を、第二引数にキー、第三引数にデフォルト値を受け取ります。受け取った第一引数が``ArrayAccess``のインスタンスでなく且つ配列でもないものならデフォルト値を戻す、キーが``null``なら第一引数をそのまま戻す。第一引数が``ArrayAccess``で且つ、その中に第二引数がオフセットとして存在する場合、若しくは第一引数が配列であり且つ第二引数がキーとして存在する場合は第一引数の第二引数オフセット、もしくは第一引数配列のキーが第二引数の値を戻す。第二引数に「``.``」が含まれていない場合は、第一引数の第二引数オフセットもしくは第一引数配列にキーが第二引数の値があればそれを、なければ第三引数デフォルト値を戻す。冗長な部分があるきがしますが、気にせず次に行きましょう。

ここからがメインです。キーを「``.``」で分割し配列にし``foreach()``で回します。 「``.``」で区切られた文字列の値で第一引数をネストして、オフセットであるか、配列のキーに存在するかを確認していきます。正当性の確認が取れた場合第一引数から第二引数の「.」記法で指定されたオブジェクト若しくは配列を戻し、正当性が取れない場合はデフォルト値を戻します。 まぁ、平たく言えばドットシンタックスを使ってオブジェクトか配列を階層構造を追って取得する感じでしょうか。 本題に戻りましょう。

## $this->items
``Arr::get()``の挙動は理解できましたがこれが引数として受け取る``$array``がまだ追えていません。``config``の定数なのではないかと予想はできますが、一応追ってみましょう。``Arr::get``を呼び出している``Repository::get()``には、``Arr::get($this->items, $key, $default)``とあります。``$this->items``は``Repository``クラスのコンストラクタでセットされるもののようです。このインスタンスは``DatabaseManager``インスタンスの``$this->app['config']``で、``$this->app``は``DatabaseManager::__construct``で``$app``がセットされています。つまり **Laravelアプリケーション自体で初期化したもの**であるだろうと推測できます。

## 次回
次回は**Larabelアプリケーションの初期設定の流れ**を追ってみましょう。