01.25
Symfony2は、登録された機能(バンドル)の情報を読み込み、結果ひとつのDIコンテナを生成します。
生成されたDIコンテナはcacheディレクトリの中に格納され、二回目以降は
このコンテナを参照するようになっています。
各サービスの情報を集約した結果がPHPのクラスとして出力されるのが
通常のパターンですが、ソースを見る限りでは違った出力方法も用意されているようです。
その中に、
Symfony\Component\DependencyInjection\Dumper\GraphvizDumper
というダンパーが存在します。
このクラスは、DIコンテナの中身を解析して、DOT言語を出力します。
これをGraphvizを使って画像に変換することで、DIコンテナの中身を
グラフィカルに表現することが可能になります。
とういわけで、さっそくsandboxのDIコンテナを画像に変換してみようと試みました。
あらかじめ、Graphvizがインストールされていることが前提条件となります。
Graphvizが存在しない場合は、以下のサイトからダウンロードすることができます。
http://www.graphviz.org/
当初は、ダンパーをPhpDumperからGraphvizDumperに交換してやることで、
容易に目的を達成できるかと思いましたが、フレームワーク内PhpDumperの使用箇所は変更できないみたいです。
仕方ないので、Actionの中に、ごりごりコードを書いていきます。
※ 環境は2011/01/23 時点のsandboxです。
GraphvizDumperのコンストラクタにはCotainerBuilderを与えてやる必要があるので、Kernelの
initializeContainerあたりを参考に、バンドルを登録し終えたContainerBuilderを再現していきます。
$parameterBag = new ParameterBag($kernel->getKernelParameters());
$container = new ContainerBuilder($parameterBag);
foreach ($kernel->getBundles() as $bundle) {
$bundle->registerExtensions($container);
}
$resolver = new LoaderResolver(array(
new YamlFileLoader($container)
));
$loader = new DelegatingLoader($resolver);
$kernel->registerContainerConfiguration($loader);
この後コンパイルを行う必要がありますが、ContainerBuilder自身のcompileメソッドを実行すると
ParameterBagが凍結されてしまい、エラーになってしまいます。
ですので、Compilerクラスのcompileを利用します。
$compiler->compile($container);
GraphvizDumperのdump()で、dotファイルを吐き出します。
dump()メソッドにオプション指定することで、フォントの種類やサイズ、背景色なども
変更できたりします。GraphvizDumperのソースを見て頂けると、どのような
オプションが指定できるか確認できるかと思います。
これをGraphvizで、画像を生成します。

実際の画像はこちら
※フォントサイズを若干いじっています。
各サービスが、どのサービスと依存しているのかが、矢印のつながりで把握できますね。
ただ、あまり細かいことは反映してくれないようです。
コマンドラインから画像生成してもいいのですが、せっかくなので
アクション内ですべて完結させてみました。
namespace Application\GraphvizBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\DependencyInjection\Dumper\GraphvizDumper;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\DelegatingLoader;
use Symfony\Component\DependencyInjection\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Compiler\Compiler;
use Symfony\Component\HttpFoundation\Response;
class GraphvizController extends Controller
{
public function indexAction()
{
$kernel = $this->get('kernel');
$parameterBag = new ParameterBag($kernel->getKernelParameters());
$container = new ContainerBuilder($parameterBag);
foreach ($kernel->getBundles() as $bundle) {
$bundle->registerExtensions($container);
}
$resolver = new LoaderResolver(array(
new YamlFileLoader($container)
));
$loader = new DelegatingLoader($resolver);
$kernel->registerContainerConfiguration($loader);
$compiler = new Compiler();
$compiler->compile($container);
$dumper = new GraphvizDumper($container);
file_put_contents('/tmp/container.dot', $dumper->dump());
exec('/usr/local/bin/dot -Tpng /tmp/container.dot > /tmp/container.png');
$png = file_get_contents('/tmp/container.png');
return new Response($png, 200, array('Content-Type'=>'image/png'));
}
}
Symfony2が今後変更されると、上記のコードは動かなくなる可能性大ですのでご了承ください。
DIコンテナを画像で表示する事で幸せになれるかはさておき、
こんなこともできたよ、ということで。
No Comment.
Add Your Comment