サンプルアプリケーション
今回もサンプルアプリケーションで実際のコードを確認しながら説明していきます。この例では「ParamSample」という名前で作成します。
$ catalyst.pl ParamSample
また、サンプルではビューを使用しますので、「<MyApp>_create.pl」を使用してビューを作成しておきます。ヘルパスクリプトに渡すパラメータは次のようになります。
$ <MyApp>_create.pl view 作成するビューモジュール名 使用するヘルパモジュール名
今回のサンプルではビューモジュールとして「Catalyst::View::TT」を使用しますので、次のようにパラメータを指定してヘルパスクリプトを実行します。
$ ./ParamSample/script/ParamSample_create.pl view TT TT
exists "/home/test/ParamSample/script/../lib/ParamSample/View" exists "/home/test/ParamSample/script/../t" created "/home/test/ParamSample/script/../lib/ParamSample/View/TT.pm" created "/home/test/ParamSample/script/../t/view_TT.t"
本記事のサンプルコードは、すべてUTF-8で保存しています。
URLパスの取り扱い
:Regexや:Pathアトリビュートなどを使用すれば、コントローラのネームスペースに依存することなくパスを自由に定義することが出来ます。ここからはパスの一部を引数として受け取る方法や一部が重複するパスを別々に定義した場合に、どのような基準でアクションにマッチするのか、について説明します。
パスの一部を引数として受け取る
これまで説明したように、パスの一部を引数として渡すことができますが、「$c->req->args」から取得する以外に、メソッドの引数として受け取ることも出来ます。次の例では、正規表現アクションで2つの引数を受け取る場合のアクション定義を示します。正規表現アクションの場合には、定義したパターンの末尾が「$」である必要があります(そうしなければどこからが引数か区別がつけられないため)。
次の例では、Root.pm(ParamSample::Controller::Root)に引数を2つ受け取る「twoargs」アクションを定義しています。
package ParamSample::Controller::Root;
# 省略
sub twoargs :Regex('^twoargs$') {
my ( $self, $c, $first, $second ) = @_;
$c->response->body( "First: $first, Second: $second" );
}
メソッドの最初の行で、「@_」から自分自身である「$self」、コンテキスト「$c」の後に、「$first」、「$second」と2つの引数を受け取っています。そしてレスポンスにそれぞれの値を表示させるようにしています。
次のURLをブラウザで表示させた場合には、$firstに「aaa」が、$secondに「bbb」が設定されていることを確認することが出来ます。
http://<ホスト名またはIPアドレス><:Port>/twoargs/aaa/bbb
ここで、「/twoargs/aaa」のように2番目のパス要素が省略された場合には、$secondには未定義値が割り当てられます。
指定したパスにマッチする基準
それではパスの一部が重なる場合に、どのような基準で実行するアクションが決められるのでしょうか? 次のように先頭から「boo/foo/woo」に重複するパスを定義した場合について考えます。
| パス | アクション |
| boo | boo |
| boo/foo | foo |
| boo/foo/woo | woo |
上の表にあるアクションをRoot.pmに定義してみると次のようになります。
package ParamSample::Controller::Root;
# 省略
sub boo :Path('boo') {
my ( $self, $c, $first, $second ) = @_;
$c->response->body( "First: $first, Second: $second at boo" );
}
sub foo :Path('boo/foo') {
my ( $self, $c ) = @_;
$c->response->body( 'boo/foo' );
}
sub woo :Path('boo/foo/woo') {
my ( $self, $c ) = @_;
$c->response->body( 'boo/foo/woo' );
}
ここで次のURLをブラウザで表示させると、「woo」アクションが実行されていることが確認できます。
http://<ホスト名またはIPアドレス><:Port>/boo/foo/woo
このように、リクエストされたパスが複数の定義にマッチする場合には、一致部分がもっとも長いアクションに処理が割り当てられます。
もし、次のように全く同じパス「/a/b」が割り当てられる場合には、Catalystが最初に見つけたアクションが実行されるため、環境やバージョンによっては呼び出されるアクションが異なる場合があります。
package ParamSample::Controller::Root;
# 省略
sub match_a_b :Path('/a/b') {
my ( $self, $c ) = @_;
$c->response->body( 'Path /a/b' );
}
package ParamSample::Controller::A;
# 省略
sub b :Local {
my ( $self, $c ) = @_;
$c->response->body('b in ParamSample::Controller::A');
}
よってこのように複数の定義が重なるようなURLを定義すべきではありません。

