Chained Examples

Quick introduction to Chained

Assume you have URLs like: /things/1/edit, /things/1/display etc. With Catalyst::DispatchType::Chained, you can separate the processing of the things/1/ bit into its own method. In this example, the method that handles the /things/1/ bit would probably do something like fetch a record from a database and put it in the stash.


Using chained actions, you can separate out parts of your application based on the accessed path. For example you may want:

Across two controllers, the definitions needed would be:

package MyApp::Controller::Account;
use parent 'Catalyst::Controller';
# match /account
sub base :Chained("/") :PathPart("account") :CaptureArgs(0) {}
# match /account sub base :Chained("/") :PathPart("account") :CaptureArgs(0) {}
# match /account (end of chain) sub root :Chained("base") :PathPart("") :Args(0) {}package MyApp::Controller::Account::Org; use parent 'Catalyst::Controller'; # match /account/org sub base :Chained("/account/base") :PathPart("org") :CaptureArgs(0) {}
# match /account/org sub base :Chained("/account/base") :PathPart("org") :CaptureArgs(0) {}
# match /account/org (end of chain) sub list :Chained("base") :PathPart("") :Args(0) {}# match /account/org/* sub id :Chained("base") :PathPart("") :CaptureArgs(1) {}# match /account/org/* (end of chain) sub view :Chained("id") :PathPart("") :Args(0) {}# match /account/org/*/edit (end of chain) sub edit :Chained("id") :PathPart("edit") :Args(0) {}

Filling out the code a little more, you'd get:

package MyApp::Controller::Account;# base sub for matching public path /account
# -- this verifies logged-in-ness for everything chained onto it
sub base :Chained("/") :PathPart("account") :CaptureArgs(0) {
  my($self, $c) = @_;  if (!$c->user_exists) {
}# display /account page
sub root :Chained("base") :PathPart("") :Args(0) {
  $c->stash->{template} = "account/";
}package MyApp::Controller::Account::Org;# nothing to do here except match the public path /account/org
# "/account" in the :Chained attribute refers to the path_prefix/namespace
# that is implicit in MyApp::Controller::Account
# the URL is "/account" because of the :PathPart("account"), which is separate
sub base :Chained("/account/base") :PathPart("org") :CaptureArgs(0) { }# match public path /account/org and display all orgs
sub list :Chained("base") :PathPart("") :Args(0) {
  my($self, $c) = @_;  $c->stash->{orgs} = $c->model("DB::Org")->search();
  $c->stash->{template} = "";
}# match public path /account/org/* and load the org record
sub id :Chained("base") :PathPart("") :CaptureArgs(1) {
  my($self, $c, $org_id) = @_;  $c->stash->{org} = $c->model("DB::Org")->find($org_id);
}# match public path /account/org/*
# display the org record, already loaded for us
sub view :Chained("id") :PathPart("") :Args(0) {
  my($self, $c) = @_;  $c->stash->{template} = "";
}sub edit :Chained("id") :PathPart("edit") :Args(0) :FormConfig("org.yml") {
  my($self, $c) = @_;  my $form = $c->stash->{form};  if ($form->submitted_and_valid) {
    $c->res->redirect($c->uri_for("/account/org", $c->stash->{org}->id));
  }  $c->stash->{template} = "";