Yii 2: 簡単にデフォルトの設定を書き換える方法

## はじめに
Yii 2 でアプリケーションを作っていく中で、ある特定のクラスのデフォルト値を変更したい、なんて場合があるかと思います。動的にオプションパラメータなどを指定して変更することもできますが、よく使うクラスのオプションパラメータはすべてこういう値にしておきたい、とか出てきた場合にはめんどうです。さてどうしましょう？ `\Yii::$container->set()` を使いましょう！

## その前に

`\Yii::$container->set()` を使わずともアプリケーション全体で使えるいくつかの便利な機能があるので、ひとまずそれらを紹介します。

### `\Yii::$app->params`
これはアプリケーション全体で使える定数みたいなものです。yii\web|console\Application クラスを new して run() したときに 'params' というキーを与えて差し入れます。yii2-app-basic を Composer でインストールした場合でいうと config/params.php に予め管理者のメールアドレスとして以下のようなものが用意されています (config/web.php, console.php では require でこのファイルを読み込んでいる) 。

```php:params.php
return [
    'adminEmail' => 'admin@example.com',
];
```

呼び出したい場合は `\Yii::$app->params['adminEmail']` とします。結果、キーに対応する値 `admin@example.com` が返されます。web, console どちらのアプリケーションでも使えます (そういう設定がされている場合) 。PHP の定数を使いたくなった場合ぐっと我慢してこちらを使うようにしましょう (PHP の定数を使わざるを得ない場合を除く) 。

もう一つは、これも yii\web|console\Application クラスを new して run() したときに与える配列です。Yii で予め提供されているコンポーネントのパラメータやクラスなどを独自のものに差し替えることができます。yii2-app-basic でいうと config/web.php や console.php などがそれに当たります。web.php で設定されているものはウェブアプリケーション全体に、console.php で設定されているものはコンソールアプリケーション全体に適用されます。かなり強力で便利です。

では、それ以外のものは？

## `\Yii::$container->set()` を使う

それ以外のものは `\Yii::$container->set()` を使うと良いかもしれません。たとえば特定のデータベーステーブルに作成日時を挿入する create_time, 更新日時を挿入する update_time というカラムがあったとしましょう。Yii 2 ではモデルを保存するときに自動でこれらのカラムにタイムスタンプを挿入する [TimestampBehavior](http://www.yiiframework.com/doc-2.0/yii-behaviors-timestampbehavior.html) というビヘイビアがあります。モデルでは以下のように設定します。

```php:Hoge.php
use yii\behaviors\TimestampBehavior;

public function behaviors()
{
    return [
        [
            'class' => TimestampBehavior::className(),
            'createdAtAttribute' => 'create_time',
            'updatedAtAttribute' => 'update_time',
        ],
    ];
}
```

createdAtAttribute プロパティの値はデフォルトでは created_at, updatedAtAttribute プロパティは updated_at なのでそれらの値を書き換えます。これでモデルを保存するとタイムスタンプも自動で挿入してくれるので非常に便利です。ただ、他のモデルでもすべて create_time, update_time というカラム名になっていた場合、 使う毎に createdAtAttribute, updatedAtAttribute プロパティの値をまた書き換えないといけないことになり、ちょっとめんどうじゃないですか？

そういう場合に `\Yii::$container->set()` を使います。早速設定していきましょう。

config/web.php と console.php に以下を追加します。

```php:web.php
require __DIR__ . '/container.php';
```

config/container.php というファイルを作成して以下のようにします。

```php:container.php
\Yii::$container->set('yii\behaviors\TimestampBehavior', [
    'createdAtAttribute' => 'create_time',
    'updatedAtAttribute' => 'update_time',
]);
```

TimestampBehavior クラスのプロパティを独自の値に差し替えている感じです。これで完了です。

TimestampBehavior ビヘイビアを使いたいモデルではプロパティの差し替えは必要なくなったので以下のようにすっきり書くことができるようになりました！

```php:Hoge.php
use yii\behaviors\TimestampBehavior;

public function behaviors()
{
    return [
        TimestampBehavior::className(),
    ];
}
```

また別のところではページ移行するときの URL の 'page' を 'p' に、あと 'per-page' という文字を付加しないようにすべて変更したいとしましょう。コントローラなどで書いた Pagination クラスのパラメータを直接変更しますか？Pagination クラスをほとんど使わないのであれば問題ないですが、よく使うのであれば以下のようにできます。

```php:container.php
$container = \Yii::$container;

// yii\behaviors
$container->set('yii\behaviors\TimestampBehavior', [
    'createdAtAttribute' => 'create_time',
    'updatedAtAttribute' => 'update_time',
]);

// yii\data
$container->set('yii\data\Pagination', [
    'pageParam' => 'p',
    'pageSizeParam' => false,
]);
```

ビューで厄介なウィジェットのオプションパラメータなどもこれで多少はすっきりするのではないでしょうか。

## 注意点

`\Yii::$container->set()` はアプリケーション全体に影響を及ぼすので、できる限り早い段階で設定しておくこと。あと \yii\data\Pagination クラスなどを単体で使用する場合などは以下のようにする必要があります。

```php:HogeController.php
$query = Hoge::find();
$countQuery = clone $query;

// $pagination = new Pagination([ ではなく
$pagination = Yii::createObject([
    'class' => Pagination::className(),
    'totalCount' => $countQuery->count(),
]);
```

モデルで指定したビヘイビアや \yii\base\Widget クラスを継承したウィジェット、\yii\data\ActiveDataProvider などは内部で `Yii::createObject()` が使われているため上記のように何か修正する必要はありません。

## まとめ

Yii 1.x には widgetFactory コンポーネントというウィジェットのみで使える、デフォルトの設定を書き換える機能があったんですが、それの強力版みたいなもんですかね？30 クラスくらい設定して速度的にどうかなどまた検証してみたいと思います。

## 関連リンク

- [Configurations](http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html)
- [Dependency Injection Container](http://www.yiiframework.com/doc-2.0/guide-concept-di-container.html)
- [Yii2 かんたんコンテナ](http://qiita.com/ytake/items/c70f741be2304d52d810)