組み込みアクション
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
アクションではブックマークの一覧を表示するためのテンプレートファイルを指定しています。