CatalystのViewでHTML::Templateを使ってみました。
ググってみると、みんなTTを使ったやりかたばかり紹介されていて、ボクはHTML::Templateの方が好きなので、敢えてHTML::Templateを使ってみました。
でも、使ってみて分かったけれど、CatalystではTTを使った方が便利かも。
でもTTだと、使い方しだいなところはあるけれどTTの便利さを活かすとMVCの分離がグレーになる気がする。HTML::Templateは制限がある分(不便な分?)MVCのVの分離が(自然と)きちんとできる気がする。
んでも、HTML::TemplateだとやっぱりCatalystを使うメリットが薄くなってしまうかなぁ。
Catalystで使うならHTML::TemplateよりHTML::template::Compiledがいいかな。こっちだと大分便利だし、煩雑なコードを大分減らせる。TTほど多機能ではないけれど、オブジェクトをセットできる分、HTよりはCatalystとの相性が良い。まぁCatalystに限らず、DBIx::Classとの相性もいい。
さて、前置きが長くなりましたが、今回はCatalystのViewでHTML::templateを使った場合の簡単な実装例についてです。
まずは、下準備として以下のテスト・モジュールをインストール。
これらはインストールしなくてもCatalystのインストールは可能です。
cpan Test::Pod
cpan Test::Pod::Coverage
さて、それでは普通にCatalystをインストール。
下記サイトからインストール・スクリプトをダウンロード。
http://www.shadowcatsystems.co.uk/static/cat-install
ダウンロードしたら実行。
perl cat-install
perl -MCPAN -e 'install Catalyst::Devel'
(現在は cpan コマンドで Task::Catalyst をインストールすることで全部インストールできるらしい)
表示を自動化する為に下記プラグインをインストール。
cpan Catalyst::Plugin::DefaultEnd
このプラグインが無かったころは、コントローラの中でいちいちどのビューで表示するかforward指定しないといけませんでした。
(現在は DefaultEndプラグインの代わりにActionClass('RenderView')を使うので、インストールする必要はありません。)
ViewにHTML::Templateを使用するので下記モジュールをインストール。
cpan HTML::Template
cpan Catalyst::Helper::View::HTML::Template
これでとりあえずインストールは完了。
次にCatalystでサンプル用のHelloプロジェクトを作成。
cd /var/www/
catalyst.pl Hello
DefaultEndを使うためにプラグインを設定。
cd /var/www/Hello
vi lib/Hello.pm
use Catalyst qw/
-Debug ConfigLoader Static::Simple DefaultEnd
/;
ビューを自動的に表示させる為に下記記述を行う
vi lib/Hello/Controller/Root.pm
sub end : ActionClass('RenderView') {}
HTML::Templateを使用したビュー、HTを作成。
script/hello_create.pl view HT HTML::Template
作成したビューを修正。下記修正をしないと表示時にエラーになります。
vi lib/Hello/View/HT.pm
__PACKAGE__->config(
die_on_bad_params => 0,
);
何故エラーになるかと言うと、テンプレートに対してCatalystが持っているもろもろのオブジェクト(stash)をセットしようとしてしまう為。
次にサンプル用のテンプレートを作成。
デフォルトのテンプレートrootはroot/baseになります。
そこに文字列を表示するだけの簡単なtestテンプレートを作成。
mkdir root/base/sample
vi root/base/sample/test.tmpl
messages: <TMPL_VAR NAME="messages"><br />
次にサンプル用のコントローラを作成。
testテンプレートに文字列'テスト'を設定。
script/hello_create.pl controller Sample
vi lib/Hello/Controller/Sample.pm
sub test : Local {
my ( $self, $c ) = @_;
$c->stash->{messages} = 'Hello World!';
}
これで一応準備は完了。
実行してみる。ポート8080で公開。
script/hello_server.pl -p 8080 -r
下記URLにアクセス。
http://localhost:8080/Sample/test
'Hello World!'と表示されればOK。
次にデータベースからデータを取得して、表示してみる。
まずは、モデルを作成するためにDBIC関連のモジュールをインストール。
cpan Catalyst::Helper::Model::DBIC::Schema
cpan DBIx::Class::Schema::Loader
そしてデモル DBICを作成。DBはMySQLを使用しています。
script/hello_create.pl model DBIC DBIC::Schema Hello::Schema create=static DBI:mysql:DB名 接続ユーザ名 接続パスワード
(1行で入力)
静的にスキーマを作成する方法をとっています。動的に生成する方法もありますが、ここでは静的で。
HelloプロジェクトにDBへの接続情報を設定します。
YAMLで書かれた設定ファイルに設定します。
vi hello.yml
name: Hello
Model::DBIC:
schema_class: Hello::Schema
connect_info:
- DBI:mysql:DB名
- DB接続ユーザ名
- DB接続パスワード
DBとテーブルは既にできているものとします。
'User'テーブルがあって、名前とかメールアドレスが保存されているものとします。
次にテーブルの情報を表示できるHTMLテンプレートを作ります。
'User'テーブルの情報を表示するテンプレートにします。
<TMPL_VAR>のNAMEは'User'テーブルのカラム名と同じにします。
vi root/base/Samle/list.tmpl
<TMPL_LOOP NAME=users>
<TMPL_VAR NAME=userid> :
<TMPL_VAR NAME=username> :
<TMPL_VAR NAME=email><br>
</TMPL_LOOP>
次にコントローラを修正。
モデルの検索結果(DBの検索結果)をテンプレートにセットします。
下記例では、単純に'User'テーブルから検索キーの指定なしで全部のレコードを取得しています。
HTML::TemplateはDBIx:Classの検索結果のオブジェクト(DBIx:Class::ResulSet)をそのままセットすることはできないので、配列、ハッシュのリファレンスにします。
vi lib/Hello/Controller/Sample.pm
sub list : Local {
my ( $self, $c ) = @_;
my @users = ();
for my $user ($c->model('DBIC::User')->all) {
push @users, {
userid => $user->userid,
username => $user->username,
email => $user->email,
};
}
$c->stash->{users}=\@users;
}
ちなみにHTML::Templae::Comipledなら同じテンプレートでも下記のような感じでOK。
<TMPL_LOOP>の為にオブジェクトを無名配列に入れてセットしています。
vi lib/Hello/Controller/Sample.pm
sub list : Local {
my ( $self, $c ) = @_;
$c->stash->{users}=\@{[ $c->model('DBIC::User')->all ]};
}
さて、これでもう一回実行し直して、URLにアクセス。
script/hello_server.pl -p 8080 -r
http://localhost:8080/Sample/list
'User'テーブルに入っているレコードの情報が全て表示されればOK。
上記コントローラの例を見ると、HTML::Templateだとテンプレートにオブジェクトを直接セットできないので面倒だなぁと思ってします。
よくウェブで公開されているビューがTTの例だと、オブジェクトをそのままセットできるので、テンプレートの為にハッシュや配列を作る必要がない。
それで、HTML::Templateの代わりにHTML::Template::Compiledを使用する場合は、テンプレートを下記のように記述すれば、TTの様にオブジェクトを直接セットできます。
HTML::template::Compiled専用のテンプレートを作成。HTML::templateでは使えません。
vi root/base/Samle/list.tmpl
<TMPL_WHILE users.next>
<TMPL_VAR _.userid> :
<TMPL_VAR _.username> :
<TMPL_VAR _.email><br>
</TMPL_WHILE>
上記テンプレートの場合、コントローラはこんな感じ。
検索キーは何も指定していません。
vi lib/Hello/Controller/Sample.pm
sub list : Local {
my ( $self, $c ) = @_;
$c->stash->{users} = $c->model('DBIC::User')->search({}, {});
}
これだけ。
DBの検索結果のオブジェクトがO-Rマッパーになっていて、テンプレートにそのオブジェクトをセットしている。
オブジェクトのアクセサ・メソッドがカラム名になっていて、それをテンプレートから直接呼び出している感じ。
楽チンで、しかも直感的で分かりやすい。
TTでも似たような感じになります。
念のために補足しておくと、HMTL::Template::Compiledを使用する場合は、そのビューを作成する必要があります。手順的にはHTML::Templateと同様です。
cpan HTML::Template::Compiled
cpan Catalyst::Helper::View::HTML::Template::Compiled
script/hello_create.pl view HTC HTML::Template::Compiled
ビューを指定して表示させたい場合は、コントローラで以下の様にforward指定します。
vi lib/Hello/Controller/Root.pm
#sub end : ActionClass('RenderView') {}
sub end : Private {
my ( $self, $c ) = @_;
$c->forward( $c->view('HTC') );
}
とりあえず、こんな感じ。
