Laravel Masterクラスを作成

#はじめに

LaravelのConfigとかLangクラス的な感じでMaster項目を管理するクラスが欲しかった。
Configは環境設定を定義する感じなので(まあ他のことにも使ってはいいだろうけど)
同じような感じでMaster項目(例えば会社名とか住所とかのシステムの環境に依存しないもの)
を定義して呼び出すクラスを作ってみた。

#方針
1. 大前提としてクラスの名前はMasterにしたい。(エンジニアにも意識してもらいたい)
のでConfigとは別クラスにする。
2. あとはとりあえずMaster::get('company.name')みたいな感じでget()が使えればOK。
3. StaticではなくFacadeを使ってUnitテストにも対応する。

#コード
上記を踏まえた上でConfigクラスの処理を追ってMasterクラスを作成。
~~ていうかConfigクラス丸コピでもよかったんじゃ…~~

```php:root/to/laravel/app/src/Master.php
<?php
namespace src;

class Master
{
    public $defaultPath;
    public $parsed;
    public $items;

    public function __construct($defaultPath = null)
    {
        $this->defaultPath = ($defaultPath) ? $defaultPath : str_replace("\\", '/', substr(__DIR__, 0, -4)) . '/master/';
    }

    /**
     * Get the specified configuration value.
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function get($key, $default = null)
    {
        list($namespace, $group, $item) = $this->parseKey($key);

        // Configuration items are actually keyed by "collection", which is simply a
        // combination of each namespace and groups, which allows a unique way to
        // identify the arrays of configuration items for the particular files.
        $collection = $this->getCollection($group, $namespace);

        $this->load($group, $collection);
        return array_get($this->items[$collection], $item, $default);
    }

    /**
     * Load the configuration group for the key.
     *
     * @param  string  $group
     * @param  string  $namespace
     * @param  string  $collection
     * @return void
     */
    protected function load($group, $collection)
    {
        // If we've already loaded this collection, we will just bail out since we do
        // not want to load it again. Once items are loaded a first time they will
        // stay kept in memory within this class and not loaded from disk again.
        if (isset($this->items[$collection]))
        {
            return;
        }

        $items = $this->getRequire($group);

        $this->items[$collection] = $items;
    }

    public function parseKey($key)
    {
        // If we've already parsed the given key, we'll return the cached version we
        // already have, as this will save us some processing. We cache off every
        // key we parse so we can quickly return it on all subsequent requests.
        if (isset($this->parsed[$key]))
        {
            return $this->parsed[$key];
        }

        // If the key does not contain a double colon, it means the key is not in a
        // namespace, and is just a regular configuration item. Namespaces are a
        // tool for organizing configuration items for things such as modules.
        if (strpos($key, '::') === false)
        {
            $segments = explode('.', $key);

            $parsed = $this->parseBasicSegments($segments);
        }
        else
        {
            $parsed = $this->parseNamespacedSegments($key);
        }

        // Once we have the parsed array of this key's elements, such as its groups
        // and namespace, we will cache each array inside a simple list that has
        // the key and the parsed array for quick look-ups for later requests.
        return $this->parsed[$key] = $parsed;
    }

    /**
     * Parse an array of basic segments.
     *
     * @param  array  $segments
     * @return array
     */
    protected function parseBasicSegments(array $segments)
    {
        // The first segment in a basic array will always be the group, so we can go
        // ahead and grab that segment. If there is only one total segment we are
        // just pulling an entire group out of the array and not a single item.
        $group = $segments[0];

        if (count($segments) == 1)
        {
            return array(null, $group, null);
        }

        // If there is more than one segment in this group, it means we are pulling
        // a specific item out of a groups and will need to return the item name
        // as well as the group so we know which item to pull from the arrays.
        else
        {
            $item = implode('.', array_slice($segments, 1));

            return array(null, $group, $item);
        }
    }

    /**
     * Parse an array of namespaced segments.
     *
     * @param  string  $key
     * @return array
     */
    protected function parseNamespacedSegments($key)
    {
        list($namespace, $item) = explode('::', $key);

        // First we'll just explode the first segment to get the namespace and group
        // since the item should be in the remaining segments. Once we have these
        // two pieces of data we can proceed with parsing out the item's value.
        $itemSegments = explode('.', $item);

        $groupAndItem = array_slice($this->parseBasicSegments($itemSegments), 1);

        return array_merge(array($namespace), $groupAndItem);
    }

    /**
     * Get the collection identifier.
     *
     * @param  string  $group
     * @param  string  $namespace
     * @return string
     */
    protected function getCollection($group, $namespace = null)
    {
        $namespace = $namespace ?: '*';

        return $namespace.'::'.$group;
    }

    /**
     * Get the returned value of a file.
     *
     * @param $group
     * @return mixed
     * @throws RuntimeException
     */
    public function getRequire($group)
    {
        $path = $this->defaultPath . $group . '.php';
        if ($this->isFile($path)) return require $path;

        throw new \RuntimeException("File does not exist at path {$path}");
    }

    /**
     * Determine if the given path is a file.
     *
     * @param  string  $file
     * @return bool
     */
    public function isFile($file)
    {
        return is_file($file);
    }

}

```

#終わりに
あとはFacadeに対応すればOK。Laravelのコードってきれいに書いてありますね。おわり。