Last modified: Mon Oct 23 20:19:56 JST 2006
そんなCatalystですが、 まずは論より証拠、自分自身で試用してみることにしました。実用性に欠ける次のような制約ありますが
、細かな作り込みや完全な機能を持っていませんが、とりあえず作ってみます。
本記事で利用した環境は以下のとおりです。
Catalystおよび関連モジュールのインストール時にも色々と質問をされますが、 これも基本的にデフォルトで問題は無いと思います。しかし、後々開発作業をし ている際によく以下の様な"Can't locate * in @INC"といった様なエラーが出て くることが時折あるかと思います。その際には該当モジュール(下記の例では Inflect.pm")を手動で追加してください。
このなかで"lib"および"root"ディレクトリ以下で開発を進めていきます。
さて、ではテスト動作をさせてみましょう。以下のコマンドを実行します。
上記のメッセージにあるように、TCP3000番にHTTPで接続できるとあります(こ
こで"astra.homeip.net"というのは作業しているPCのホスト名です)のでブラウ
ザでアクセスしてみます。URLに"http://localhost:3000/"などと指定して右の
画面が表示されればインストールはOKです。
このミニサーバーが起動しなかった場合、"Can't locate XXX.pm in @INC"(XXX の部分はいろいろ)などとエラーメッセージが出ていませんか?必要なモジュー ルがインストールされていないかもしれません。XXXで指摘されたモジュールを インストールしてください。
ミニサーバーを起動したターミナルの方ではデバッグ用のメッセージが出力され るようになります。フォームに入力した値などの他、各種の動作状況、エラーメッ セージが出力されますので、逆スクロールできるターミナル、例えばEmacsの Shell modeなどの中で利用するのが良いと思います。
このミニサーバーを終了するときには起動したコンソールで^C(Ctrl+C)としてください。
今回はビューにTemplate-Toolkit、モデルにClass::DBIを利用することとします。 というわけで、以下のCPANモジュールを新たにインストールしました。
データベースのスキーマは今回【リスト1】に示した様な1つのテーブルにまとめ た形式とします。本来ならオリジナルのメッセージとそれに対するコメント文と を別テーブルにするところなのかもしれませんが、今回は実装例の説明なので、 コンパクトにまとまるようにしました。
Catalystを使ったアプリケーションの作成
- はじめに
- 例題〜掲示板〜
- インストール&動作確認
- 設計
- データベース構築
- コーディング
- 動作確認
- サービス用の配備の方法(mod_perlでの利用) 2006/10/15追加
- ページ機能の追加(Class::DBI::Pagerの利用 方法)2006/10/22追加
- セッションの維持(プラグインモジュール
の利用)(予定)
1. はじめに
最近、Ruby on Railsを始めとして各種プログラミング言語におけるWebアプリケーションの フレームワークに関する話題がホットです。種々のプロダクトがある中で、Java におけるStruts の様に定番の地位を不動のものにしたものがある一方で、PHPのように乱立状態 の様相を呈しているものもあります。そんな中でPerlでは昨年(2006年9月現在) あたりから、高い拡張性、既存のCPANモジュールとの親和性を「ウリ」としたCatalystがMVCフレー ムワークとして注目されてきています。ただ新しいこともあってか、日本語情報 が少ないのが現状です。そんなCatalystですが、 まずは論より証拠、自分自身で試用してみることにしました。
2. 例題〜掲示板〜
仕様
さしあたって例題としては簡単な掲示板を作ってみました。スレッド式のもので、 オリジナルメッセージにコメントを追記できるようなものです。ただし目的はあ くまでCatalystの試用なので、スレッドは全て1ページに表示。1ページあたりの表示スレッドは固定では なく無限。
Class::DBI::Pagerを利用した機能拡張により、ページ機能が追加されました。 (10/22追記)スレッドの並び方は書き込みが古いものから(笑)
これは解決しました。書き込みは新しいものから表示されるように改良。詳細 は後述。(10/15追記)
前提プロダクト
本掲示板では記事の永続化方式にはRDBMSのPostgreSQLを使用します。ただしPostgreSQLに特有な機能は 利用していないのでMySQLへの移植などは容易でしょ う。この他、Catalystは多くのCPANモジュールを必要とします。が、これは Catalyst本体のインストール時に自動的に入るものもありますし、あとから手で 入れる必要があるものもあります。詳細はインストールの項目で説明します。 Webサーバは実サービス時にはApacheなどが必要とな りますが、開発段階ではCatalystで用意されている専用ミニ サーバーが利用できます。このミニサーバーはデバッグ用情報が十分に 出力されるなど、なかなか便利なものです。本記事で利用した環境は以下のとおりです。
- OS: FreeBSD 5.4-RELEASE
- PostgreSQL: ver.7.4.7
- Perl: 5.8.6
- Catalyst: ver.5.6902
インストール・動作確認
インストール
Catalystは相当数の他モジュールに依存しています。ですからモジュールをひと つひとつ手作業でインストールすることは現実的ではありません。そこで、 CatalystではCPANから"Task::Catalyst"というモジュー ルをインストールすることで連鎖的に必要なモジュールが自動的にインストール される様になっています。ただインストール中、[y/n]でオプションを選択させ られる場面が多々ある上、モジュール数もインストール前の環境に依存しますが、 相当数(私の場合30 あまり)ですので、所要時間はそれなりにかかります。 インストールには次のコマンドをroot権限で実行します。ただしこの方法ではイ ンストールされるモジュールがrootのホームディレクトリに全て展開されること に注意してください。また"-MCPAN"オプション(CPANサイトからモジュールを取 得してインストールまでを自動化するオプション)を初めて使用する場合には、 対話式にモジュールの展開場所を訊かれますので、そこで"/usr/local/src"等、 適当な場所に変えておくのも一つの方法です。
$ su
Password:
# perl -MCPAN -e 'install Task::Catalyst'
#
もし"-MCPAN"オプションでCPANからのインストールをするのが初めてであれば、
その際にもあれこれと質問をされます。基本的に全てデフォルトでよいと思いま
すが、先ほど説明したようにモジュールの展開場所を変えたい場合、該当個所を
変えてください。Password:
# perl -MCPAN -e 'install Task::Catalyst'
#
Catalystおよび関連モジュールのインストール時にも色々と質問をされますが、 これも基本的にデフォルトで問題は無いと思います。しかし、後々開発作業をし ている際によく以下の様な"Can't locate * in @INC"といった様なエラーが出て くることが時折あるかと思います。その際には該当モジュール(下記の例では Inflect.pm")を手動で追加してください。
"Can't locate Lingua/EN/Inflect.pm in @INC (@INC
contains: /home/hiraku/src/msgboard/MsgBoard/script/../lib
/usr/local/lib/perl5/site_perl/5.8.6/mach
/usr/local/lib/perl5/site_perl/5.8.6 /usr/local/lib/perl5/site_perl
/usr/local/lib/perl5/5.8.6/BSDPAN /usr/local/lib/perl5/5.8.6/mach
/usr/local/lib/perl5/5.8.6 .)
個々のモジュールの追加の場合でも以下の様にperlの"-MCPAN"オプションを使用
することで逐一インストールすることができます。
$ su
Password:
# perl -MCPAN -e 'install Inflect'
#
Password:
# perl -MCPAN -e 'install Inflect'
#
動作確認
それでは動作確認をしてみましょう。今回の例題のアプリケーション名はMsgBoardとします。開発は以後ディレクトリ"~/src"以下で行うものとします。この例と環境が違う場合 には適宜この部分を読み替えてください。コマンド"catalyst.pl MsgBoard"を実行します。するとアプリケーショ ン開発に必要なディレクトリ構成が作成されます。
$ cd ~/src
$ catalyst.pl MsgBoard
created "MsgBoard"
created "MsgBoard/script"
created "MsgBoard/lib"
created "MsgBoard/root"
created "MsgBoard/root/static"
created "MsgBoard/root/static/images"
created "MsgBoard/t"
created "MsgBoard/lib/MsgBoard"
created "MsgBoard/lib/MsgBoard/Model"
created "MsgBoard/lib/MsgBoard/View"
created "MsgBoard/lib/MsgBoard/Controller"
created "MsgBoard/msgboard.yml"
created "MsgBoard/lib/MsgBoard.pm"
created "MsgBoard/lib/MsgBoard/Controller/Root.pm"
created "MsgBoard/README"
created "MsgBoard/Changes"
created "MsgBoard/t/01app.t"
created "MsgBoard/t/02pod.t"
created "MsgBoard/t/03podcoverage.t"c
created "MsgBoard/root/static/images/catalyst_logo.png"
created "MsgBoard/root/static/images/btn_120x50_built.png"
created "MsgBoard/root/static/images/btn_120x50_built_shadow.png"
created "MsgBoard/root/static/images/btn_120x50_powered.png"
created "MsgBoard/root/static/images/btn_120x50_powered_shadow.png"
created "MsgBoard/root/static/images/btn_88x31_built.png"
created "MsgBoard/root/static/images/btn_88x31_built_shadow.png"
created "MsgBoard/root/static/images/btn_88x31_powered.png"
created "MsgBoard/root/static/images/btn_88x31_powered_shadow.png"
created "MsgBoard/root/favicon.ico"
created "MsgBoard/Makefile.PL"
created "MsgBoard/script/msgboard_cgi.pl"
created "MsgBoard/script/msgboard_fastcgi.pl"
created "MsgBoard/script/msgboard_server.pl"
created "MsgBoard/script/msgboard_test.pl"
created "MsgBoard/script/msgboard_create.pl"
結果として次のようなディレクトリ構成がつくられます。
$ catalyst.pl MsgBoard
created "MsgBoard"
created "MsgBoard/script"
created "MsgBoard/lib"
created "MsgBoard/root"
created "MsgBoard/root/static"
created "MsgBoard/root/static/images"
created "MsgBoard/t"
created "MsgBoard/lib/MsgBoard"
created "MsgBoard/lib/MsgBoard/Model"
created "MsgBoard/lib/MsgBoard/View"
created "MsgBoard/lib/MsgBoard/Controller"
created "MsgBoard/msgboard.yml"
created "MsgBoard/lib/MsgBoard.pm"
created "MsgBoard/lib/MsgBoard/Controller/Root.pm"
created "MsgBoard/README"
created "MsgBoard/Changes"
created "MsgBoard/t/01app.t"
created "MsgBoard/t/02pod.t"
created "MsgBoard/t/03podcoverage.t"c
created "MsgBoard/root/static/images/catalyst_logo.png"
created "MsgBoard/root/static/images/btn_120x50_built.png"
created "MsgBoard/root/static/images/btn_120x50_built_shadow.png"
created "MsgBoard/root/static/images/btn_120x50_powered.png"
created "MsgBoard/root/static/images/btn_120x50_powered_shadow.png"
created "MsgBoard/root/static/images/btn_88x31_built.png"
created "MsgBoard/root/static/images/btn_88x31_built_shadow.png"
created "MsgBoard/root/static/images/btn_88x31_powered.png"
created "MsgBoard/root/static/images/btn_88x31_powered_shadow.png"
created "MsgBoard/root/favicon.ico"
created "MsgBoard/Makefile.PL"
created "MsgBoard/script/msgboard_cgi.pl"
created "MsgBoard/script/msgboard_fastcgi.pl"
created "MsgBoard/script/msgboard_server.pl"
created "MsgBoard/script/msgboard_test.pl"
created "MsgBoard/script/msgboard_create.pl"
【ディレクトリ構成】
各ディレクトリに収められる内容物は次の通りです。
MsgBoard/
+- Makefile.PL
+- Changes
+- README
+- msgboard.yml
+- lib/
+- root/
+- script/
+- t/
| ディレクトリ | 内容 |
|---|---|
| lib | 下位でさらにController/Model/Viewのディレクトリに別れている。 開発者が実装するコントローラ/モデル/ビューそれぞれのコードを配置する。 この時点ではアプリケーションの設定を収める"lib/MsgBoard.pm"と、リクエストされたURLに応じて処 理をディスパッチする"lib/MsgBoard/Controller/Root.pm"が予め生成されて いる。 |
| root | ユーザーが実際に見る静的ページや動的ページのテンプレートを格納する。 |
| t | テスト用コードを格納する。(詳細はまた時を改めて) |
| script | テスト用ミニサーバー、開発をサポートする各種スクリプトが格納されてい る。 |
| msgboard.yml | このファイルにYAML形式でアプリケーションの構成情報、パラメータなどを 設定する。 |
| README, Changes | 説明するまでもないですね。 |
さて、ではテスト動作をさせてみましょう。以下のコマンドを実行します。
$ ~/src/MsgBoard/script/msgboard_server.pl
....(略)....
[Sun Sep 17 18:15:34 2006] [catalyst] [info] MsgBoard powered by Catalyst 5.6902
You can connect to your server at http://astra.homeip.net:3000
....(略)....
[Sun Sep 17 18:15:34 2006] [catalyst] [info] MsgBoard powered by Catalyst 5.6902
You can connect to your server at http://astra.homeip.net:3000
上記のメッセージにあるように、TCP3000番にHTTPで接続できるとあります(こ
こで"astra.homeip.net"というのは作業しているPCのホスト名です)のでブラウ
ザでアクセスしてみます。URLに"http://localhost:3000/"などと指定して右の
画面が表示されればインストールはOKです。このミニサーバーが起動しなかった場合、"Can't locate XXX.pm in @INC"(XXX の部分はいろいろ)などとエラーメッセージが出ていませんか?必要なモジュー ルがインストールされていないかもしれません。XXXで指摘されたモジュールを インストールしてください。
ミニサーバーを起動したターミナルの方ではデバッグ用のメッセージが出力され るようになります。フォームに入力した値などの他、各種の動作状況、エラーメッ セージが出力されますので、逆スクロールできるターミナル、例えばEmacsの Shell modeなどの中で利用するのが良いと思います。
このミニサーバーを終了するときには起動したコンソールで^C(Ctrl+C)としてください。
3. 設計
モデル、ビュー用モジュールの選択
Catalystのコアの部分そのものは、主としてコントローラ部分を担っており、 ビュー、モデルの部分は別途作成しなければなりません。しかしCatalystの特徴 のひとつである、他のモジュールとの親和性がここで生かされます。例えば、 ビューの部分はCPANモジュールである、HTML::Template、Template-Toolkitなどを自由に選択することもできますし、 今回の様にデータの永続化にデータベースを利用するのであれば、同じくCPANモ ジュールである。Class::DBIなどをを利用する ことができます。今回はビューにTemplate-Toolkit、モデルにClass::DBIを利用することとします。 というわけで、以下のCPANモジュールを新たにインストールしました。
- Class-DBI-v3.0.14
- Catalyst-Model-CDBI-0.11.tar.gz
- Class-DBI-Pg-0.09.tar.gz
データベース設計
今回利用するデータベースは前述のようにPostgreSQL(ver.7.4.7)です。ただし バージョン依存があるような機能は特に利用していませんので、ver.8.0以上な どでも問題はないはずです。データベースのスキーマは今回【リスト1】に示した様な1つのテーブルにまとめ た形式とします。本来ならオリジナルのメッセージとそれに対するコメント文と を別テーブルにするところなのかもしれませんが、今回は実装例の説明なので、 コンパクトにまとまるようにしました。
【リスト1】データベースのスキーマ
各属性の意味は次表のとおりです。
create table message (
id integer primary key default nextval('sequence_message'),
title text,
author text not null,
item text not null,
date timestamp (0) default current_timestamp,
ref integer default 0
);
| 属性名 | 役割 |
|---|---|
| id | プライマリーキーです。メッセージ、コメントのIDを示します。投稿時に自動 的に採番されていくように、PostgreSQLのシーケンス機能を使って値を挿入 します。その為、上記のスキーマをデータベースに登録する前に、「シーケン ス」を作成しておく必要があります。 |
| title | 元メッセージ(スレッドの先頭のメッセージ)につく記事のタイト ル。コメントの場合は必要ないので"not null"制約は不要とします。 |
| author | 元メッセージ、コメントの投稿者の名前。必須なので"not null"制約を付与し ます。 |
| date | メッセージ、コメントが投稿された日時。投稿された日時に自動的に現在時刻 が入るようにDefault値をcurrent_timestampに設定します。 (0)の意味は1秒以下の精度を指定する意味です。(10/15追記) |
| item | メッセージ、コメントの文章本体です。必須なので"not null"制約を付与しま す。 |
| ref | 元メッセージの場合は、この値は0になります。コメントの場合は、対象とな る元メッセージのidが入り関連づけがなされます。 |
画面設計
画面は以下の二つのみです。- メイン画面
- 元メッセージ、コメントの一覧表示と新規投稿のフォームが入ります。
- コメント投稿画面
- メイン画面中、各スレッドに関連づけられている「コメント」ボタンを
押すとこの画面に遷移します。この画面では元メッセージとコメント投稿
用のフォームが表示されます。
データ構造
スクリプト中でのデータ構造は【リスト2】の様に設計します。画面上の構造をそ のまま表現した形ですが、多少構造が複雑なのはご容赦ください。これをコント ローラの中で作成してビューコンポーネントに引き渡す様にします。
【リスト2】データ構造
my @page = ( # ページ全体を保持
(
origmsg => { # スレッドの元メッセージ
title => '最初のスレッドのタイトル',
date => '投稿の日時',
author => '投稿者の名前',
text => '本文',
},
comment => [
{ # 1番目のコメント
date => '投稿の日時',
author => '投稿者の名前',
text => '本文',
},
{ # 2番目のコメント
date => '投稿の日時',
author => '投稿者の名前',
text => '本文',
},
]
),
(
##.... 二番目のスレッド ....
),
);
参考リンク・文献
- インプレスコミュニケーションズ:まるごとPerl!Vol1
- 技術評論社:WEB+DB PRESS vol.32(2006/4)「Perlフレームワークの大本命Catalyst入門」
- Catalyst::Manual::Intro(日本語訳)
- Catalyst::Manual::Cookbook(日本語訳)
Since 2003