ここ1ヶ月ほど(ながいなぁ…)、ちまちまと勉強してきたCGI::Application::Dispatchについて、使い方もこなれて来たので、ここいらでひとまとめです。
何するモジュール?
この勉強中エントリーの1回目でも書きましたが、CGI::Applicationを利用したアプリで必要になるインスタンスCGIは作らずに、URI(PATH_INFO)から実行するモジュールとRunモードを決定する、というモジュールです。newしてrunするだけのインスタンスCGIなんか毎回書きたくないよ、というのがモジュール作者さんの意図のようです(PODにもあります)。
URIはこうなる
CGI::Application::Dispatchを使った場合のURIは、
/どこか/モジュール名/Runモード # mod_perl使う
/どこか/dispatch.cgi/モジュール名/Runモード # mod_perl使わない
となります。
CGI::Applicationを継承したMyApp::Indexというモジュールを作った場合、それを実行するためのURIを比較すると以下のようになります。
- 通常のCGI::Application
http://example.com/index.cgi http://example.com/index.cgi?rm=mode1
- CGI::Application::Dispatch(mod_perlなし)
http://example.com/dispatch.cgi/index/ http://example.com/dispatch.cgi/index/mode1
- CGI::Application::Dispatch(mod_perlあり)
http://example.com/app/index/ http://example.com/app/index/mode1
通常のCGI::Applicationのみを使った場合、実行するモジュールごとにインスタンスCGIを追加する必要があります。それが、mod_perlなしのCGI版の場合は1つのCGIのみ、mod_perlを利用してApacheのハンドラとしてDispatchを利用する場合はCGIは必要ありません。
dispatch.cgiの中身
単純なdispatch.cgiの中身は以下のようになります。
#!/usr/bin/perl
use lib qw(/path/to/mylib);
use CGI::Application::Dispatch;
CGI::Application::Dispatch->dispatch(
PREFIX => 'MyApp',
DEFAULT => 'Index',
);
この設定だけでパッケージ名が「MyApp::**」なモジュールすべてが実行可能です。DEFAULTで指定したモジュールは、その名のとおりで、
http://example.com/dispatch.cgi http://example.com/dispatch.cgi/
というモジュール指定のないURIでアクセスされたときに実行するモジュールを指定します。
DispatchテーブルでURl/モジュールマッピング
実際にCGI::Applicationを使っていると、MyApp::Hoge::Fugaというような深い名前空間の階層を持つモジュールや、単純にパッケージ名が長いモジュールが出てくることががあります。こういったときにはTABLEを使って、URIとモジュール名をマップさせます。
#!/usr/bin/perl
use lib qw(/path/to/mylib);
use CGI::Application::Dispatch;
CGI::Application::Dispatch->dispatch(
PREFIX => 'MyApp',
DEFAULT => 'index',
TABLE => {
index => 'Index',
fuga => 'Hoge::Fuga',
bar => 'Hoge::Foo::Bar',
},
);
このようにした場合のURIは、
http://example.com/dispatch.cgi/index/ => MyApp::Index
http://example.com/dispatch.cgi/fuga/ => MyApp::Hoge::Fuga
http://example.com/dispatch.cgi/bar/ => MyApp::Hoge::Foo::Bar
となります。TABLEハッシュのキーがURIのモジュール名部分になります。便宜上「モジュール名」としていますが、実際にはただのハッシュのキーなので何でも設定可能です。また、TABLEを指定した場合は、DEFAULTの値は実際のモジュール名ではなくハッシュのキーに指定した値で指定します。
MultiViewsを使った拡張子のないURI
良いURI設計の条件として「技術を丸出しにしない」ということがあるそうです(参考)。ここでいう「技術」とは、拡張子.cgiがURIに含まれることで、サーバー側の実装技術が(実際にCGIとして機能しているかどうかは別に)URIに現れてしまっていることです。
拡張子をURIから取り除く方法としては、mod_rewriteを使うのが一般的ですが、今回の勉強中にApacheのMultiViewsオプションでも実現できることを知ったのでそちらを紹介します。(海賊たろさんに感謝)。
dispatch.cgiが設置されているディレクトリのhtaccessまたは、httpd.confに以下を追加します。
AddHandler cgi-script .cgi
Options +MultiViews +ExecCGI
MultiviewsMatch Handlers # これがミソ
設定はこれだけで、これまで、
http://example.com/dispatch.cgi/index/mode2
としてきたURIを、
http://example.com/dispatch/index/mode2
というURIでアクセスできるようになります。かっこいい。このミソポイントの内容にについてはこちらを参照。
(Dispatch自体には直接関係ありませんが…)。
「HTML内のURI参照は相対パス派」の人向け
これまでCGI::Applicationを、
- PATH_INFO未使用
- tmpl_path()未使用でインスタンスCGIとテンプレートは同じ階層
- HTML内のURI参照は相対パス
という感じで使ってきた人にとっては、Dispatchモジュールはちょっとてこずると思います(自分がそうでした…)。その原因はこちらのエントリーでも書きましたが、すべてのURIがPATH_INFOを使って、
/dispatch.cgi/モジュール名/Runモード
で表され、同じ階層のURIになるためです。インスタンスCGIっていうものが無いので、最初のうちはテンプレートをどこにおいたらいいんだろう???と迷います。これに関しては、かぜぶろさんの方法が激しく参考になります。DispatchテーブルとMultiViewsのサンプルもこのレイアウトを頂いています。
参考とか
- CGI::Application::Dispatch
- yohei-y:weblog: 良い URI の設計
- [僕] ディレクトリ構成とか
- blog.nomadscafe.jp: PATH_INFOと相対パス(リンク)
- naoyaのはてなダイアリー - UNIX USER Perl の短期集中連載 No.3
過去の関連エントリー
おしまい。