Catalyst::Manual::Intro - はじめてのCatalyst
ここではなぜ、またどうやってCatalystを使うのかを簡単に紹介します。Catalystの挙動について説明し、簡単なアプリケーションを手早く立ち上げる様子をご覧に入れます。
Catalystとはエレガントなウェブ・アプリケーション・フレームワークです。きわめて柔軟なのにきわめてシンプル。Ruby on RailsやSpring (Java)、そしてCatalystの元となったMaypoleによく似ています。
Catalystはモデル・ビュー・コントローラ(MVC)というデザイン・パターンを踏襲しているため、コンテンツ、プレゼンテーション、フロー管理といった問題を簡単に切り分けて独立したモジュールにすることができます。こうして切り分けることで他の問題を処理するコードに影響を与えることなく、ひとつの問題を扱うコードのみを修正することができるようになります。Catalystは一般的なウェブ・アプリケーションの問題を上手に処理してくれる既存のPerlモジュールの再利用を奨励します。
次に、M、V、Cがこれらの問題とどう結びつけられるかを、みなさんが使いたいと思われるであろう有名なPerlモジュールの実例とともに紹介します。
コンテンツ(データ)にアクセスしたりデータを修正したりします。 Class::DBI、 Plucene、 Net::LDAP...
コンテンツをユーザの目に見える形にします。 Template Toolkit、 Mason、 HTML::Template...
リクエスト・フェーズ全体の管理、パラメータのチェック、アクションのディスパッチ、フロー管理。 Catalyst!
MVCやデザイン・パターンに不慣れな方は、Gamma、Helm、Johson、Vlissides、またの名をGang of Four (GoF)の手になるこのテーマの原典、Design Patternsをチェックしておいた方がよいかもしれません。Googleで検索するだけでもよいでしょう。本当に多くのウェブ・アプリケーション・フレームワークがMVCをベースにしています。上記のフレームワークもすべてそうです。
Catalystは他の多くのフレームワークに比べてはるかに柔軟です。詳しくはまた後で紹介しますが、Catalystなら間違いなくお好きなPerlモジュールを使えると思ってください。
Catalystアプリケーションを組むときは「コンポーネント」と呼ばれる専用モジュールの中でそれぞれの問題を処理します。このコードはしばしば非常にシンプルな、「MVC」の項で取り上げたPerlモジュールを呼び出すだけのものになります。Catalystはこれらのコンポーネントを非常に柔軟な方法で処理します。使うモデル、ビュー、コントローラの数はお好きなように。使うPerlモジュールの種類もお望みのまま。すべてを同じアプリケーションの中に同居できます。いくつものデータベースを操作して、一部のデータはLDAPで取り出したい? 問題ありません。同じモデルのデータをTemplate ToolkitとPDF::Templateを使って吐き出したい? 簡単です。
Catalystは既存のPerlモジュールを再利用するよう奨励するだけではありません。自作したCatalystのコンポーネントは複数のCatalystアプリケーションで再利用できます。
CatalystはあらゆるURLからあらゆるアプリケーションのアクションへとディスパッチできます。正規表現を使うこともできるのです! 他のほとんどのフレームワークと違って、mod_rewriteは必要ありませんし、URLにクラスやメソッドの名前を含める必要もありません。
Catalystを使えばアクションの登録とディスパッチ先の指定が直接できます。たとえば
sub hello : Global {
my ( $self, $context ) = @_;
$context->response->body('Hello World!');
}
これでhttp://localhost:3000/helloが「Hello World!」と表示するのです。
何よりすばらしいのは、Catalystがこれらの柔軟性を非常にシンプルな方法で実装していることです。
コンポーネントの相互運用は実にスムーズです。たとえば、Catalystはすべてのコンポーネントで利用可能なコンテキストオブジェクトを自動的に作成します。コンテキストを経由すればリクエスト・オブジェクトにもアクセスできますし、コンポーネント同士のデータ共有や、アプリケーション・フローの管理もできます。Catalystアプリケーションを組むのはおもちゃの積み木を組み合わせるようなものですが、それで万事うまくいってしまうのです。
自作したコンポーネントを何から何までuseする必要はありません。Catalystが自動的に探してロードしてくれます。
Class::DBIにはCatalyst::Model::CDBI、Template ToolkitにはCatalyst::View::TTが用意されています。
Catalystにはあらかじめ軽量のhttpサーバとテスト・フレームワークが用意されているので、コマンド・ラインから簡単にアプリケーションのテストができます。
Catalystについてくるヘルパー・スクリプトを使うと、すぐに実行できるコンポーネントやユニット・テスト用のスターター・コードを生成できます。Catalyst::Helperをご覧ください。
では、前述したヘルパー・スクリプトを使ってCatalystをインストールし、簡単なアプリケーションを実行してみましょう。
$ perl -MCPAN -e 'install Task::Catalyst'
$ catalyst.pl MyApp
# (出力は省略)
$ cd MyApp
$ script/myapp_create.pl controller Library::Login
$ script/myapp_server.pl
では、Catalystが動いているのを確かめるために、お好きなブラウザ、ユーザ・エージェントで以下のURLにアクセスしてみてください。
死ぬほど簡単でしょ!
さて、Catalystはどのように動作しているのでしょう。Catalystアプリケーションのコンポーネントなどをもっとよく見ていきましょう。
モデル、ビュー、コントローラといったコンポーネントに加えて、アプリケーションそのものをあらわすクラスがひとつあります。ここでアプリケーションの設定をしたり、プラグインをロードしたり、アプリケーション全体に関わるアクションを定義したり、Catalystを拡張したりします。
package MyApp;
use strict;
use Catalyst qw/-Debug/;
MyApp->config(
name => 'My Application',
# これ以外に何を書いても結構です。
my_configuration_variable => 'something',
);
sub default : Private {
my ( $self, $context ) = @_;
$context->response->body('Catalyst rocks!');
}
1;
たいていのアプリケーションの場合、ここで定義しなければならない設定パラメータは1つのみです。
アプリケーション名です。
オプションとして、テンプレートや静的データの位置を示すrootパラメータを指定することもできます。このパラメータを省略すると、Catalystはディレクトリの位置を自動的に検出しようとします。また、プラグインなどに必要なパラメータはいくらでも定義できます。このパラメータはアプリケーションのどこからでも$context->config->{$param_name}でアクセスできます。
Catalystはコンテキスト・オブジェクトを自動的にアプリケーション・クラスにブレスして、アプリケーションのどこからでもアクセスできるようにします。Catalystと直接やりとりしたり、コンポーネントを互いにのり付けするときにはコンテキストを使ってください。たとえば、Template Toolkitのテンプレートの中からコンテキストを使う必要があるなら、使ってください。すでに使えるようになっていますから。
<h1>Welcome to [% c.config.name %]!</h1>
URLからアクションへとディスパッチする例で見たように、コンテキストは常にメソッドの2番目のパラメータになります。その前にはコンポーネント・オブジェクトのリファレンスや、クラス名そのものが来ます。先だってはわかりやすさを優先して$contextと表記しましたが、Catalystの開発者はたいてい$cと書くだけで済ませます。
sub hello : Global {
my ( $self, $c ) = @_;
$c->res->body('Hello World!');
}
コンテキストにはいくつかの重要なオブジェクトが含まれています。
$c->request
$c->req # alias
リクエスト・オブジェクトにはクエリのパラメータやクッキー、アップロード、ヘッダなど、あらゆる種類のリクエスト固有の情報が含まれています。
$c->req->params->{foo};
$c->req->cookies->{sessionid};
$c->req->headers->content_type;
$c->req->base;
$c->response
$c->res # alias
The response is like the request, but contains just response-specific information.
$c->res->body('Hello World');
$c->res->status(404);
$c->res->redirect('http://oook.de');
$c->config
$c->config->root;
$c->config->name;
$c->log
$c->log->debug('Something happened');
$c->log->info('Something you should know');
$c->stash
$c->stash->{foo} = 'bar';
この最後のスタッシュというのは、アプリケーション・コンポーネントの間でデータを共有するのに使うユニバーサル・ハッシュです。たとえば、先ほどの「hello」アクションに戻ってみましょう。
sub hello : Global {
my ( $self, $c ) = @_;
$c->stash->{message} = 'Hello World!';
$c->forward('show_message');
}
sub show_message : Private {
my ( $self, $c ) = @_;
$c->res->body( $c->stash->{message} );
}
スタッシュは1つの独立したリクエスト・サイクルの中でデータを渡すときにのみ使うように注意してください。新しいリクエストが来るとスタッシュはクリアされます。もっと長い間データを維持する必要があるときはセッションを使ってください。
Catalystのコントローラはアクションの組み合わせによって定義されます。アクションとは特別な属性を持ったsubのことです。このドキュメントの中でもすでに何度か例が登場しました。URL(たとえばhttp://localhost.3000/foo/bar)は、ベース(この例の場合はhttp://localhost:3000/)とパス(foo/bar)という2つの部分からなります。ホスト名[:ポート]の後のスラッシュは、アクションではなく、かならずベースに属するということに注意してください。
Catalystは何通りかのアクションをサポートします。
package MyApp::Controller::My::Controller;
sub bar : Path('foo/bar') { }
Pathというリテラルのアクションは、現在の名前空間に対する相対パスになります。上の例の場合、http://localhost:3000/my/controller/foo/barにのみマッチします。パスをスラッシュで始めた場合はルートからのパスにマッチします。たとえば、
package MyApp::Controller::My::Controller;
sub bar : Path('/foo/bar') { }
は、http://localhost:3000/foo/barにのみマッチします。
package MyApp::Controller::My::Controller;
sub bar : Path { }
Pathの定義を空にしておくと、名前空間のルートにマッチします。上のコードの場合、http://localhost:3000/my/controllerにマッチします。
sub bar : Regex('^item(\d+)/order(\d+)$') { }
たとえばhttp://localhost:3000/item23/order42のように、アクション・キーのパターンにマッチするあらゆるURLにマッチします。正規表現を囲む''はなくてもかまいませんが、perltidyはある方が好みです(^_^)
正規表現のマッチはグローバルに行われます。つまり、呼び出し元の名前空間は考慮されません。そのため、MyApp::Controller::Catalog::Order::Processの名前空間にあるbarメソッドは、正規表現で明示的に指定しない限り、bar、Catalog、Order、Processのいずれともマッチしません。マッチさせたい場合はLocalRegexアクションを使うことを検討してください。
sub bar : LocalRegex('^widget(\d+)$') { }
LocalRegexのマッチはローカルに行われます。上の例では、http://localhost:3000/catalog/widget23のようなURLにマッチします。
この正規表現で「^」を省略すると、コントローラ名の直下ではなく、コントローラのどの階層ともマッチするようになります。次の例の場合は、上のコードとは違ってhttp://localhost:3000/catalog/foo/widget23にもマッチします。
package MyApp::Controller::Catalog;
sub bar : LocalRegex('widget(\d+)$') { }
LocalRegexの場合もRegexの場合も、( )を使ってマッチしたURLに含まれる値を抽出する場合、抽出した値は$c->req->snippetsという配列の中に入ります。上の「widget23」の例では「23」が抽出されて、$c->req->snippets->[0]に「23」が入ります。URLの末尾で引数の受け渡しをしたい場合はアクション・キーに正規表現を使う必要があります。後述する「URLパスの扱い」をご覧ください。
package MyApp;
sub foo : Global { }
http://localhost:3000/fooにマッチします。関数名がアプリケーションのベースに直接マップされます。
package MyApp::Controller::My::Controller;
sub foo : Local { }
http://localhost:3000/my/controller/fooにマッチします。
このアクション・タイプでは、マッチするURLの前にかならずコンポーネントのクラス(パッケージ)名を補正したものがつきます。ここで言う補正というのは、クラス名からCatalystで事前に意味が定義されている部分(上の例では「MyApp::Controller」)を取り除き、「::」を「/」で置き換え、名前部分を小文字に変換することを指します。補正の詳細については「コンポーネント」をご覧ください。
sub foo : Private { }
どのURLにもマッチしません。また、アクション・キーに対応するURLをリクエストしても実行できません。プライベート・アクションはCatalystアプリケーション内部でforwardメソッドを呼んだときのみ実行できます。
$c->forward('foo');
forwardの詳細については「フロー管理」をご覧ください。そちらで説明しますが、別のコンポーネントからforwardするときはメソッドへの絶対パスを指定する必要があります。つまり、MyApp::Controller::Catalog::Order::Processコントローラのプライベート・メソッドbarを別の場所から呼ぶときには$c->forward('/catalog/order/process/bar')のように呼び出す必要があるということです。
注意:こういった例を見ると、正規表現やパスのアクションで名前を定義する目的は何なのだろうかと不思議に思われるかもしれません。実は、パブリック・アクションはいずれもプライベート・アクションでもあります。だから、forwardを使えば統一的な方法でコンポーネントの位置を指定することができます。
Catalystはアプリケーションが特定の状態になると自動的にアプリケーション・クラスの中でこれらのビルトイン・プライベート・アクションを呼び出します。
他にマッチするアクションがない場合に呼び出されます。たとえば、メイン・アプリケーションの一般的なフロントページを表示するときや、個々のコントローラのエラー・ページを表示するときに利用できます。
defaultが期待通りの動作をしない場合は、リテラルのPathアクションを(パス文字列なしで)使ってみてください。両者の違いは、Pathの方は名前空間からの相対パスが引数になるのに対して、defaultの方はどのコントローラからであろうと常にルートからの相対パスが引数になるところです。
indexはdefaultによく似ていますが、引数をとらず、マッチ処理の際に少しだけ優先順位が高くなります。コントローラに対する静的なエントリ・ポイントとして、つまり静的な入口ページをつくるときに利用すると便利です。また、パスより優先順位が高くなっていることにも注意してください。
リクエストの最初、マッチするあらゆるアクションが呼ばれる前に呼び出されます。
リクエストの最後、マッチするすべてのアクションが呼ばれた後に呼び出されます。
Package MyApp::Controller::Foo;
sub begin : Private { }
sub default : Private { }
sub auto : Private { }
ビルトイン・プライベート・アクションはコントローラの中で定義することもできます。コントローラの中で定義したアクションは、より階層が上のコントローラ、あるいはアプリケーション・クラスの中で定義されたアクションをオーバーライドします。つまり、3つのビルトイン・プライベート・アクションはそれぞれ一度のリクエスト・サイクルの中では1つずつしか実行されないということです。だから、MyApp::Controller::Catalog::beginが存在していたら、catalogという名前空間の中ではそれがMyApp::beginのかわりに実行されますし、MyApp::Controller::Catalog::Order::beginというのが存在していたら、今度はこれがMyApp::C::Catalog::beginをオーバーライドします。
通常のビルトイン・アクションの他に、autoというアクションをチェーンさせるための特殊なアクションがあります。このautoが指定されたアクションは、あらゆるbeginの後、通常のアクション処理の前に実行されます。他のビルトインと違って、autoのアクションはお互いのオーバーライドをしません。アプリケーション・クラスから、最も階層の深いクラスまで順に呼び出されます。つまり、通常のビルトインがお互いのオーバーライドするときとは順序が逆になります。
さまざまなビルトインが呼ばれる順序の例をあげます。
/foo/fooへのリクエストの場合MyApp::begin MyApp::auto MyApp::Controller::Foo::default # MyApp::Controller::Foo::Fooがない場合 MyApp::end
/foo/bar/fooへのリクエストの場合MyApp::Controller::Foo::Bar::begin MyApp::auto MyApp::Controller::Foo::auto MyApp::Controller::Foo::Bar::auto MyApp::Controller::Foo::Bar::default # MyApp::Controller::Foo::Bar::fooのかわり MyApp::Controller::Foo::Bar::end
autoアクションは0を返すとチェーン処理を抜けることができるという点でも特徴的です。autoアクションが0を返した場合、end以外の残りのアクションはすべてスキップされます。だから、上のリクエストの場合、最初のautoが偽を返したら、チェーンは以下のようになります。
/foo/bar/fooへのリクエストで、最初のautoが偽を返した場合MyApp::Controller::Foo::Bar::begin MyApp::auto MyApp::Controller::Foo::Bar::end
このような使い方が必要になりそうな例としては認証アクションがあります。アプリケーション・クラスに認証を処理するautoアクションをセットアップして(これは常に最初に呼ばれます)、認証が失敗したときには0を返すようにすると、そのURLに対する残りのすべてのメソッドをスキップできます。
注意:別の見方をすると、処理を続けたければautoアクションはかならず真の値を返さなくてはならないということです! オートチェーン・アクションでdieすることもできます。その場合、リクエストはそれ以上アクションを処理することなく、一直線に最終段階まで移行します。
各種の引数はURLパスの一部に含めて渡すことができます。その場合は「^」と「$」をアンカーとした正規表現アクション・キーを使う必要があります。また、URL中の引数はスラッシュ(/)で区切る必要があります。たとえば、/foo/$bar/$bazというURLを処理するときのことを考えてみましょう。ここで$barと$bazの値は変わりうるものとします。
sub foo : Regex('^foo$') { my ($self, $context, $bar, $baz) = @_; }
では、/foo/booと/foo/boo/hooのアクションも定義したらどうなるでしょう?
sub boo : Path('foo/boo') { .. }
sub hoo : Path('foo/boo/hoo') { .. }
Catalystは最も階層の深いものから最も階層の浅いものへという順番でアクションのマッチをとります。
/foo/boo/hoo
/foo/boo
/foo # /foo/bar/bazにはなるかもしれませんが、/foo/boo/hooにはなりません
だから、Catalystが最初の2つのURLを間違って「^foo$」のアクションにディスパッチすることはありえないのです。
URLのクエリ・ストリングで渡されたパラメータはCatalyst::Requestクラスのメソッドで処理されます。このクラスのparamメソッドは機能的にCGI.pmのparamメソッドと同等ですので、CGI.pmのparamメソッドを要求するモジュールでこのクラスを使うこともできます。
# http://localhost:3000/catalog/view/?category=hardware&page=3 my $category = $c->req->param('category'); my $current_page = $c->req->param('page') || 1; # ひとつのパラメータ名で複数の値を扱うこともできます my @values = $c->req->param('scrolling_list'); # DFVはCGI.pmのような入力ハッシュを要求します。 my $results = Data::FormValidator->check($c->req->params, \%dfv_profile);
アプリケーションのフローはforwardメソッドで管理します。このメソッドは実行するアクションのキーを受け取ります。このアクションは、同じCatalystコントローラのものでも、別のCatalystコントローラのものでも、オプションとしてメソッド名が続くかもしれないクラス名でも結構です。forwardが終わると、管理フローはforwardを発行したメソッドに戻ります。
forwardはメソッド呼び出しと似ていますが、大きく違うのは、例外処理ができるよう、呼び出しをevalでくるんでいることです。forwardは自動的にコンテキスト・オブジェクト($cないし$context)を渡します。また、それぞれの呼び出しのプロファイリングも可能にします(デバッグを有効にするとログに表示されます)。
sub hello : Global {
my ( $self, $c ) = @_;
$c->stash->{message} = 'Hello World!';
$c->forward('check_message'); # $cは自動的にインクルードされます
}
sub check_message : Private {
my ( $self, $c ) = @_;
return unless $c->stash->{message};
$c->forward('show_message');
}
sub show_message : Private {
my ( $self, $c ) = @_;
$c->res->body( $c->stash->{message} );
}
forwardは新しいリクエストを作らないため、リクエスト・オブジェクト($c->req)の内容も変わりません。これがforwardを使うのとリダイレクトを発行するのとの主要な差です。
forwardに新しい引数を渡すこともできます。その引数を無名配列の中に追加してください。この場合、$c->req->argsの値はforwardしている最中のみ変更されます。forwardから返ると$c->req->argsの値も元の値にリセットされます。
sub hello : Global {
my ( $self, $c ) = @_;
$c->stash->{message} = 'Hello World!';
$c->forward('check_message',[qw/test1/]);
# ここで$c->req->argsの値は元に戻ります
}
sub check_message : Private {
my ( $self, $c ) = @_;
my $first_argument = $c->req->args[0]; # ここでの値は 'test1' です
# 何らかの処理をします…
}
これらの例から分かるように、同じコントローラのメソッドを参照する分にはメソッド名のみの指定でも大丈夫です。別のコントローラ、あるいはメイン・アプリケーションのメソッドにforwardしたいときは絶対パスでメソッドを参照する必要があります。
$c->forward('/my/controller/action');
$c->forward('/default'); # メイン・アプリケーションのdefaultが呼ばれます
クラスやメソッドにforwardする例をいくつか挙げます。
sub hello : Global {
my ( $self, $c ) = @_;
$c->forward(qw/MyApp::Model::Hello say_hello/);
}
sub bye : Global {
my ( $self, $c ) = @_;
$c->forward('MyApp::Model::Hello'); # メソッドがない場合。「process」を試行します
}
package MyApp::Model::Hello;
sub say_hello {
my ( $self, $c ) = @_;
$c->res->body('Hello World!');
}
sub process {
my ( $self, $c ) = @_;
$c->res->body('Goodbye World!');
}
forwardはアクションが終了すると呼び出し元のアクションに戻って処理を続行することに注意してください。呼び出し元のアクションに一切それ以上の処理をさせたくない場合は、かわりにdetachを使います。こちらはdetachされたアクションを実行したあと、呼び出し元のsubに戻りません。いずれにしても、メソッドを省略した場合、Catalystは自動的にprocess()を呼び出そうとします。
Catalystはけた外れに柔軟なコンポーネント・システムを持っています。モデル、ビュー、コントローラをいくらでも定義できるのです。
すべてのコンポーネントはCatalyst::Baseを継承しなければなりません。これはシンプルなクラス構造と、configやnew(コンストラクタ)といった一般的なクラス・メソッドをいくつか提供します。
package MyApp::Controller::Catalog;
use strict;
use base 'Catalyst::Base';
__PACKAGE__->config( foo => 'bar' );
1;
useなどを使ってモデルやビュー、コントローラを登録する必要はありません。メイン・アプリケーションでsetupを呼べば、Catalystが自動的にそれらを検出してインスタンス化します。しなければならないのは、それぞれのコンポーネント種別にあわせて命名されたディレクトリに配置することだけです。また、これらについてはそれぞれ非常に簡潔な別名を利用することもできます。
ビューの定義の仕方を紹介するために、既存のTemplate Toolkit用ベース・クラス、Catalyst::View::TTを利用します。しなければならないのはこのクラスから継承することだけです。
package MyApp::View::TT;
use strict;
use base 'Catalyst::View::TT';
1;
(ヘルパー・スクリプトを利用して自動生成することもできます。
script/myapp_create.pl view TT TT
最初のTTはビューの名前がTTであることをスクリプトに教えます。次のTTはそれがTemplate Toolkitのビューであることを示すものです。)
これでprocess()メソッドができました。あとはただ$c->forward('MyApp::View::TT')すればテンプレートをレンダリングできます。ベース・クラスは暗黙の了解としてprocess()しますので、$c->forward(qw/MyApp::View::TT process/)と書く必要はありません。
sub hello : Global {
my ( $self, $c ) = @_;
$c->stash->{template} = 'hello.tt';
}
sub end : Private {
my ( $self, $c ) = @_;
$c->forward('MyApp::View::TT');
}
テンプレートのレンダリングは通常リクエストの最後に行いますので、グローバルのendアクションにうってつけです。
なお、テンプレートはかならず$c->config->{root}で指定したディレクトリの下に入れてください。さもないと、あの見るも楽しいデバッグ画面を見せられることになりますよ(^_^)
モデルの定義法も既存のベース・クラスを使って紹介しましょう。今度はClass::DBIに対応するCatalyst::Model::CDBIを使います。
まずはデータベースが必要です。
-- myapp.sql
CREATE TABLE foo (
id INTEGER PRIMARY KEY,
data TEXT
);
CREATE TABLE bar (
id INTEGER PRIMARY KEY,
foo INTEGER REFERENCES foo,
data TEXT
);
INSERT INTO foo (data) VALUES ('TEST!');
% sqlite /tmp/myapp.db < myapp.sql
これでこのデータベースに対するCDBIコンポーネントを作成できます。
package MyApp::Model::CDBI;
use strict;
use base 'Catalyst::Model::CDBI';
__PACKAGE__->config(
dsn => 'dbi:SQLite:/tmp/myapp.db',
relationships => 1
);
1;
Catalystはテーブルのレイアウトや依存関係を自動的にロードします。テンプレートにデータを渡すときにはスタッシュを使ってください。
package MyApp;
use strict;
use Catalyst '-Debug';
__PACKAGE__->config(
name => 'My Application',
root => '/home/joeuser/myapp/root'
);
__PACKAGE__->setup;
sub end : Private {
my ( $self, $c ) = @_;
$c->stash->{template} ||= 'index.tt';
$c->forward('MyApp::View::TT');
}
sub view : Global {
my ( $self, $c, $id ) = @_;
$c->stash->{item} = MyApp::Model::CDBI::Foo->retrieve($id);
}
1;
# それから、TTのテンプレートにこう書きます。
idは[% item.data %]です
モデルはCatalystアプリケーションの一部である必要はありません。いつでも外部のモジュールをモデルとして呼び出すことができます。
# コントローラで
sub list : Local {
my ( $self, $c ) = @_;
$c->stash->{template} = 'list.tt';
use Some::Outside::CDBI::Module;
my @records = Some::Outside::CDBI::Module->retrieve_all;
$c->stash->{records} = \@records;
}
ただし、Catalystアプリケーションに含まれているモデルを使うといくつかの利点があります。それぞれのコンポーネントをuseする必要はありません。Catalystがコンパイル時に自動的に検索してロードします。モジュールにforwardすることもできます。これはCatalystコンポーネントにのみ可能です。また、$c->model('SomeModel')で引っ張ってこれるのもCatalystコンポーネントのみです。
幸い、多くの人々がCatalystで既存のモデル・クラスを使いたがるため(あるいは、逆にCatalystの外部で――たとえばcronのジョブとして――も使えるCatalystモデルを書きたがるため)、外部のモデルでも動くシンプルなCatalystコンポーネントも簡単に書けるようになっています。
package MyApp::Model::Catalog;
use base qw/Catalyst::Base Some::Other::CDBI::Module::Catalog/;
1;
はい、できた、と! これでSome::Other::CDBI::Module::CatalogがMyApp::Model::CatalogとしてCatalystアプリケーションの一部になるのです。
アプリケーションの論理領域を分けるにはコントローラを複数使うのが吉です。
package MyApp::Controller::Login;
sub sign-in : Local { }
sub new-password : Local { }
sub sign-out : Local { }
package MyApp::Controller::Catalog;
sub view : Local { }
sub list : Local { }
package MyApp::Controller::Cart;
sub add : Local { }
sub update : Local { }
sub order : Local { }
Catalystにはテスト用にビルトインのhttpサーバがついています!(テストを終えてプロダクション環境に移行するときにApache/mod_perlなどもっと強力なサーバに切り替えることも簡単にできます)
コマンド・ラインからアプリケーションを起動します。
script/myapp_server.pl
そして、ブラウザでhttp://localhost:3000/を開いて出力を表示させてみてください。
すべてをコマンド・ライン上で実行してしまうこともできます。
script/myapp_test.pl http://localhost/
お楽しみあれ!
IRC:
Join #catalyst on irc.perl.org.
メーリングリスト:
http://lists.rawmode.org/mailman/listinfo/catalyst http://lists.rawmode.org/mailman/listinfo/catalyst-dev
Sebastian Riedel, sri@oook.de David Naughton, naughton@umn.edu Marcus Ramberg, mramberg@cpan.org Jesse Sheidlower, jester@panix.com Danijel Milicevic, me@danijel.de
石垣憲一(ishigaki_at_tcool.org) http://www.tcool.org/
This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself.