symfonyで自前のYAML設定ファイルを勝手に読み込ませるアイデア

昨日、Twitter@massatさんが以下のようなことをつぶやかれていました。

🍻 on Twitter: "sfConfigHandler まわりの挙動を変えるプラグインを書きたいのだが。余地がないぞ・・・。 #symfony"
🍻 on Twitter: "@vectorxenon config_handlers.yml に自前のymlを記述するとsfConfigCache::importでキャッシュまで作っちゃうプラグインを作ろうと思ったのですが。importの引数で渡すパターン名をConfigHandler内で取れなくて悩み中す"
🍻 on Twitter: "app.ymlが肥大するのが嫌だから最近は自前のymlを作ってconfig_handlers.ymlに書いてsfDefineEnvironmentConfigHandlerで読んでsfConfigCache::checkConfigをincludeして使ってる。 #symfony"
🍻 on Twitter: "いちいち面倒だから、config_handlers.ymlのparamに cache: on とか書いとくとキャッシュ化までしてくれるプラグインを書こうと思ったけど、sfConfigHandlerだけだと厳しそうで、filterも使わないとダメかなと感じてる。 #symfony"

実は私も少し似たようなことを考えたことがあったので、少し調べてみました。

自前のYAML設定ファイルを使うには?

そもそも自前のYAML設定ファイルをsymfonyで使う方法をまず簡単に説明します。
と言っても、基本的なことはsymfonyのドキュメントに既に書いてあります。

このドキュメントでは、「config/map.yml」というファイルに対して独自のコンフィグハンドラークラスを作って処理していますが、YAMLファイルの処理方法がapp.ymlと同じであれば、わざわざコンフィグハンドラークラスを用意しなくても、sfDefineEnvironmentConfigHandlerで処理すれば十分です。

しかし、ここに記述したYAMLファイルの設定を実際にアプリケーションの中で有効にするには、以下のように明示的にコンフィグファイルの読み込みを実行しなくてはなりません。

<?php
include(sfContext::getInstance()->getConfigCache()->checkConfig('config/map.yml'));

app.ymlやsetting.ymlの内容は(sfApplictionConfigurationクラスなどで)自動的に読み込まれますが、自前のYAML設定ファイルは自前で読み込まないといけないので、最初に紹介した@massatさんのような意見が出たということと解釈しました。

とりあえずここまでをまとめると、

  1. 自前YAMLファイルを書く
  2. config_handlers.ymlに追加する
  3. 自前YAMLファイルを読み込ませるコードを(どこかに)書く

自動的に読み込ませるには?

例えばアプリケーションごとの(application)Configurationクラスのsetup()メソッドに、上記の設定読み込みコードを記述すれば良いのですが、設定ファイルを増やす度に上の3ステップが必要になります。
このステップを1つでも減らそうというのが本エントリの目的です。


最大のポイントは、The Definitive Guideの上で紹介したページにも書いてあるのですが、config_handlers.ymlを処理するsfRootConfigHandlerの動作などを、派生クラスの作成やイベントなどでカスタマイズする方法がないということです。


config_handlers.ymlやsfConfigCache関連の処理は、sfApplicationConfigurationクラスで行われており、ここで何とかこれらの処理をカスタマイズできないかと試してみたのが今回の方法です。


方法の概略:

  1. プラグインを作成する
  2. プラグインの(plugin)Configurationクラスのinitialize()メソッドでfalseを返す
  3. プラグインの/config/config.phpに、処理を記述する。

2のようにinitialize()メソッドでfalseを返すと、3のconfig.phpが呼ばれるようになります。
実際これは、sfApplicationConfigurationのinitializePlugin()メソッド内で処理されるのですが、config.phpをそのコンテキストでrequireしています。つまり、3のconfig.phpに処理を記述することで、sfApplicationConfigurationクラスに自前の処理を潜り込ませることができる、というわけです。


↓今回作成したプラグインのconfig.phpのコード

<?php
include($this->configCache->checkConfig('config/config_handlers.yml'));
foreach ($this->handlers as $handler_path=>$handler_config)
{
    if (strstr($handler_path, '/ex_'))
    {
        $this->configCache->import($handler_path);
    }
}

(ex_〜〜.ymlというコンフィグハンドラーの定義があれば、自動的にimportしています。)

http://github.com/hidenorigoto/sfConfigExtraPlugin

このコードはちょっと強引で、(application)Configurationに、config_handlers.ymlの設定を直接マージして処理しています。
config_handlers.ymlを読み込むと、クラスのメンバ変数($this->handlers)にコンフィグハンドラー一覧が読み込まれるのですが、もしクラスにすでにhandlersという変数がある場合は困ったことになってしまいます。ですので、将来何かの変更によって使えなくなる可能性もあります。

(というあたりで、きちんとしたプラグインとしての実装までは持っていっていません)

まとめ

symfonyYAML設定システムはとても強力なので、ちょっとしたカスタマイズ方法なども知っておくといろいろ便利です。
最後に参考URLを。

massatさんが作られたプラグインはこちら