An Introduction to Application Development with Catalyst and Perl
Dispatch
Catalyst provides a particularly flexible and powerful mechanism for configuring dispatch rules. Rather than having a separate configuration to assign URLs to specific actions, Catalyst uses the actions themselves to determine URL mappings dynamically.
Each action definition (which is just a Perl subroutine) represents not only a block of code, but also what URL paths apply to it. This is specified in subroutine attributes—a lesser-known Perl feature that provides arbitrary labels that can be used for introspection.
Catalyst supports a handful of parameterized attributes to determine the URL
path to action mappings in a variety ways.
For example, the following action has an absolute path set using the
:Path attribute:
sub myaction :Path('/some/place') {
my ( $self, $c, @args ) = @_;
# do stuff...
}
Regardless of what controller you put it in, the above action would map to all URLs starting with /some/place (http://localhost:3000/some/place with the development server).
If you omitted the starting slash and used
:Path('some/place'), the action
would map to a path relative to the namespace of the controller. For
example, if it were in KillerApp::Controller::Foobar, it would be mapped
to URL paths starting with /foobar/some/place.
Instead of using :Path to set the path explicitly,
you can set :Local to
use the name of the controller and method. For instance, the following
action, if contained in the controller
KillerApp::Controller::Some, would
also map to /some/place:
sub place :Local {
my ( $self, $c, @args ) = @_;
# do stuff...
}
If it were contained in the controller
KillerApp::Controller::Some::Other, it would map to /some/other/place.
Actions include subpaths by default, so the above also would match
/some/other/place/blah/foo/1. When this happens, the leftover parts of the
path are supplied as arguments to the action method ('blah','foo','1'). You
can use the :Args attribute to limit how deep the action will match subpaths, if at all. With an Args value of 0, this action would match only
/some/place, but nothing below it:
sub myaction :Path('/some/place') :Args(0) {
my ( $self, $c ) = @_;
# do stuff...
}
Other attributes are available too. :Global works
like :Local but
ignores the controller name, and path pattern matching can be done with
:Regex and :LocalRegex.
When a URL matches more than one action, Catalyst picks the one that
matches best. However, there are a few built-in actions (method names
"begin", "end" and "auto") that, if defined, are called at various stages
of every request in addition to the matched action. Using the advanced
:Chained attribute type, you can configure additional/multiple actions to
be called with single requests in any order you like.
You also can programmatically dispatch to other action/paths from within the action code itself:
sub myaction :Path('/some/place') {
my ( $self, $c, @args ) = @_;
$c->forward('/some/other/place');
}
The Context Object ($c)
Controller actions serve as entry points to application code. A special
per-request object called the "context" is supplied as an argument to every
action when it is called by the dispatcher. The context object typically
is read into a variable named $c, but it could be called anything.
The context provides interfaces and information about the application and
its current state. It contains the details of the request currently being
processed ($c->request) and access to what will become the response
($c->response).
At the beginning of the request, before any actions are called, the response object is created with empty/default data. Each of the actions that are called then has an opportunity to manipulate the response. At the end of the request, its final state is sent back to the client. This iterative approach to generating the response lends itself to a modular and dynamic structure.
The following action illustrates a few of the simple APIs that are available, such as inspecting the User-Agent and query/post parameters in the request, and setting the body and headers of the response:
sub myaction :Path('/some/place') {
my ( $self, $c, @args ) = @_;
my $myparam = $c->request->params->{myparam};
if(defined $myparam) {
$c->response->body("myparam is $myparam");
}
else {
$c->response->body("myparam was not supplied!!");
}
$c->response->body(
$c->response->body .
"\n\nExtra path args: " . join('/',@args)
) if (@args > 0);
$c->response->headers->header( 'Content-Type' => 'text/plain' );
$c->response->body("Bad command or file name")
if ($c->request->user_agent =~ /MSIE/);
}
Accessing the URL http://localhost:3000/some/place/boo/baz?myparam=foo would display the text that follows (except when using IE, in which case "Bad command or file name" is displayed instead):
myparam is foo
Extra path args: boo/baz
Within the action code, you can write any logic you like to build your application. Because the context object is just a variable, you can pass it as an argument into other functions. Following normal Perl programming rules, you can use other classes and libraries, instantiate objects and so on.
This is the extent of what you have to do—write controller actions and use the context object—but it's only the beginning of what you can do.
Catalyst Components
Over and above the core functionality, Catalyst provides a robust MVC structure to build your application. This includes useful base classes, sensible default behaviors and helpful sugar functions. You can leverage a tremendous amount of turnkey functionality by creating your classes within the supplied framework as models, views and controllers.
All these are considered "components" within Catalyst, and there aren't actually many functional differences between them. The Model-View-Controller monikers primarily are used for the purpose of categorization. Models are meant to contain data and business logic; views are supposed to handle rendering and display; and controllers tie everything together.
Operationally, components are essentially application classes with some extra, Catalyst-specific functionally. They are loaded automatically at startup as static object instances. Any component can be accessed throughout the application via the context object:
sub myaction :Path('/some/place') {
my ( $self, $c, @args ) = @_;
$c->model('MyModel')->do_something;
$c->forward( $c->view('MyView') );
}
In the above example action, you simply are calling the method
do_something in a model named
MyModel (KillerApp::Model::MyModel), and
then forward to the view named
MyView (KillerApp::View::MyView).
Earlier, I showed how to use forward to dispatch to another action by
supplying a path. When you pass a component to
forward, the process
method of the supplied component is called as if it were a controller
action, which is roughly equivalent to this:
$c->view('MyView')->process($c,@args);
These are just a few examples of the available conventions and shortcuts. The important thing to understand is that all these sugar functions just boil down to calling methods and normal program flow.
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
Web Development News
Developer Poll
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
| Dart: a New Web Programming Experience | May 07, 2013 |
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Home, My Backup Data Center
- RSS Feeds
- What's the tweeting protocol?
- New Products
- Trying to Tame the Tablet
- Dart: a New Web Programming Experience
- IT industry leaders
1 hour 7 min ago - Reply to comment | Linux Journal
17 hours 55 min ago - Reply to comment | Linux Journal
20 hours 28 min ago - Reply to comment | Linux Journal
21 hours 45 min ago - great post
22 hours 20 min ago - Google Docs
22 hours 42 min ago - Reply to comment | Linux Journal
1 day 3 hours ago - Reply to comment | Linux Journal
1 day 4 hours ago - Web Hosting IQ
1 day 5 hours ago - Thanks for taking the time to
1 day 7 hours ago







Comments
Error in template?
In page 3 of this article:
$c->stash->{data}->{title} = 'TT rendered page';
Shouldn't the template have this:
[% data.title %]
Instead of what is in the article:
[% title %]
This was an effective review for me, thank you!
[% data.message %] too
I should have also mentioned that given:
$c->stash->{data}->{message} = 'A cool message!';
The following in the template:
[% message %]
needs to be:
[% data.message %]
Good work
I like post a complete catalyst tutorial, i want to know if reference for it article, tks
Really nice article! Catalyst
Really nice article! Catalyst is great framework with great community behind it
typo
In this text:
The alias for
/static/above tells Apache to serve the files directly in this directory (images, CSS, JavaScript files and so on). This is more efficient than serving these files through the application, which isn't necessary.The <code> and </code> HTML tags surrounding /static/ somehow got through.
Good Job!
Nice work! I hope you'll continue with another MVC framework from Perl, a more lighter one, Perl Dancer.
Daniel
Excellent!
With so many people still thinking of perl as "that legacy language that you run from the cgi-bin directory", it's good to see the modern stuff get some coverage. Nice one!
Good work, looking for more!
Only LinuxJournal could have come up with such article. Good work!
Try to post a complete catalyst tutorial, there's only one single tutorial available (CPAN's tutorial for catalyst, the best one).