組み込みアクション
Catalystでは、リクエスト処理を実行する中で、特別な動作をする組み込みアクションが5つ用意されています。これらのアクションを定義した場合には「$c->forward」などで明示的に呼び出さなくても、Catalystの側で自動的に呼び出されます。
default
「default」アクションは、他にマッチするアクションがない場合に呼び出されます。「Root.pm」にデフォルトで作成されるdefaultアクションでは、「Page not found」を表示し、404を返します。
defaultアクションはそれぞれのコントローラで上書き(オーバーライド)できます。例えば「Bar.pm」にdefaultアクションを定義し、ネームスペースが「foo/bar」以下の存在しないパスを指定した場合には、「Bar.pm」モジュールで定義したdefaultアクションが呼び出されます。
古いバージョンのCatalystでは「default :Private」と定義されることがありますが、これらの違いは次のようになります。
例として、Bar.pmにdefaultアクションを追加した場合について考えます。ここで次のURLを指定した場合の動作について説明します。
http://<ホスト名またはIPアドレス><:Port>/foo/bar/aaa/bbb
(1)default :Path
ネームスペースからの相対パスが引数になるため、「aaa/bbb」が引数となります。
(2)default :Private
コントローラに関係なく、ルートからの相対パスが引数になるため、「foo/bar/aaa/bbb」が引数となります。
index
「index」アクションはdefaultアクションとよく似ていますが、引数を取らない、優先順位が高い、という点で異なります。
一般的には、コントローラのエントリポイントとして使用され、Welcomeページの表示やデータの一覧を表示する処理を定義します。
begin
「begin」アクションは、リクエストの最初に呼び出され、またコントローラで上書きできます。beginアクションでは、必要なデータを作成したりする場合に使用されます。例えばbeginアクションで、UserAgentからクライアントの端末が携帯電話かそれ以外かを判定し、そのフラグをStashに登録しておけば、他のアクションでは毎回端末の種別チェックをする必要が無くなります。
package HelloC::Controller::Root;
# 省略
sub begin : Private {
my ( $self, $c ) = @_;
# (1)リクエストのUserAgentから、携帯電話かそれ以外かを判定
my $user_agent = $c->req->user_agent;
$c->stash->{is_mobile} = 0 or 1;
}
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
# (2)フラグによって携帯電話/PCかどうかを判定
if ($c->stash->{is_mobile}) {
# 携帯電話用の処理
} else {
# PC用の処理
}
}
上記の例では、次のような処理を行っています。
(1)リクエストのUserAgentから、携帯電話かそれ以外かを判定
Catalyst::RequestからUserAgentを取得し、携帯電話かどうかを判定します。そして判定結果をStashに登録しています。
(2)フラグによって携帯電話/PCかどうかを判定
indexアクションでは、Stashに登録された値に基づいて携帯電話かPCかを判定し、それぞれに依存した処理を実装します。
end
「end」アクションはリクエストの最後に呼び出され、またコントローラで上書きできます。endアクションには、最後にまとめて行う処理を記述します。例えば各アクションごとにViewへのレンダリング処理を呼び出さなくても、endアクションにまとめて記述できます。デフォルトの「Root.pm」では、endアクションの定義が次のようになっています。
package HelloC::Controller::Root;
# 省略
sub end : ActionClass('RenderView') {}
ここでは、:ActionClassアトリビュートで指定したCatalyst::Action::RenderViewを使用することで、適切なViewの呼び出し処理を行っています。
auto
「auto」アクションは、beginアクションの後に呼び出されますが、他のアクションと異なり、複数のコントローラで定義した場合でも上書きされません(すべてのautoアクションが順に呼び出されます)。
autoアクションが複数のコントローラで定義されている場合、呼び出される順番はRootから始まり、順次下位のコントローラに向かって呼び出されます。
例えば、次のコントローラにautoアクションが定義されている場合を考えます。
- HelloC::Controller::Root
- HelloC::Controller::Foo
- HelloC::Controller::Foo::Bar
この場合に「Foo::Bar」のアクションにマッチするリクエストがあった場合には、次の順序でautoアクションが呼び出されます。
- HelloC::Controller::Root
- HelloC::Controller::Foo
- HelloC::Controller::Foo::Bar
また、autoアクションで0を返した場合には、それ以降のアクション呼び出しが行われません。
autoアクションでは、あるコントローラだけにとどめておきたい処理を記述します。例えば、「<MyApp>::Controller::User」と「<MyApp>::Controller::User::Bookmark」というコントローラを考えた場合、「<MyApp>::Controller::User」にはユーザーに関する前処理を、「<MyApp>::Controller::User::Bookmark」にはブックマークに関する前処理を記述することで、あちこちに実装が分散することを防ぐことができます。
package <MyApp>::Controller::User;
# 省略
sub auto :Private {
my ( $self, $c ) = @_;
# (1)ユーザ情報を取得
$c->stash->{user_info} = ...
}
package <MyApp>::Controller::User::Bookmark;
# 省略
sub auto :Private {
my ( $self, $c ) = @_;
# (2)ユーザに関連するブックマークを取得
my $user_info = $c->stash->{user_info};
$c->stash->{bookmarks} = ...
}
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
# (3)ブックマーク一覧を描画
$c->stash->{template} = 'bookmark_list.tt';
}
上記の例では、次のような処理を行っています。
(1)ユーザー情報を取得
Userコントローラのautoアクションでは、セッションなどからユーザー情報を取得してStashに登録しています。
ここでは、ブックマークなど他のコントローラに関する処理は実装していません。
(2)ユーザーに関連するブックマークを取得
User::Bookmarkコントローラのautoアクションでは、Stashに登録されているユーザー情報を元にして関連するブックマークを取得し、Stashに登録しています。
ユーザー情報に関する処理はUserコントローラに任せて、ここではブックマークに関する前処理のみを実装しています。
(3)ブックマーク一覧を描画
indexアクションではブックマークの一覧を表示するためのテンプレートファイルを指定しています。
