Catalyst is an elegant web application framework, extremely flexible
yet extremely simple. It's similar to Ruby on Rails, Spring (Java), and
L<Maypole|Maypole>, upon which it was originally based. Its most
-important design philosphy is to provide easy access to all the tools
+important design philosophy is to provide easy access to all the tools
you need to develop web applications, with few restrictions on how you
need to use these tools. However, this does mean that it is always
possible to do things in a different way. Other web frameworks are
I<initially> simpler to use, but achieve this by locking the programmer
into a single set of tools. Catalyst's emphasis on flexibility means
that you have to think more to use it. We view this as a feature. For
-example, this leads to Catalyst being more suited to system integration
+example, this leads to Catalyst being better suited to system integration
tasks than other web frameworks.
=head3 MVC
=item * B<Controller>
Control the whole request phase, check parameters, dispatch actions, flow
-control. Catalyst itself!
+control. This is the meat of where Catalyst works.
=back
Now http://localhost:3000/hello prints "Hello World!".
-Note that actions with the C< :Global > attribute are equivalent to
+Note that actions with the C< :Local > attribute are equivalent to
using a C<:Path('action_name') > attribute, so our action could be
equivalently:
ready server (although you'll probably want to run it behind a front end proxy
if you end up using it).
+=item * PSGI Support
+
+Starting with Catalyst version 5.9 Catalyst ships with L<PSGI> integration
+for even more powerful and flexible testing and deployment options. See
+L<Catalyst::PSGI> for details.
+
=back
=head3 Simplicity
# perl -MCPAN -e 'install Catalyst::Runtime'
# perl -MCPAN -e 'install Catalyst::Devel'
+ # perl -MCPAN -e 'install Catalyst::View::TT'
=head3 Setup
=item * B<MyApp/Model/>
-=item * B<MyApp/M/>
-
=item * B<MyApp/View/>
-=item * B<MyApp/V/>
-
=item * B<MyApp/Controller/>
-=item * B<MyApp/C/>
-
=back
-In older versions of Catalyst, the recommended practice (and the one
-automatically created by helper scripts) was to name the directories
-C<M/>, C<V/>, and C<C/>. Though these still work, they are deprecated
-and we now recommend the use of the full names.
-
=head4 Views
To show how to define views, we'll use an already-existing base class for the
script/myapp_create.pl model MyModel DBIC::Schema MySchema create=static 'dbi:SQLite:/tmp/myapp.db'
-L<DBIx::Class::Schema::Loader> can automaticall load table layouts and
+L<DBIx::Class::Schema::Loader> can automatically load table layouts and
relationships, and convert them into a static schema definition
C<MySchema>, which you can edit later.
From a style perspective it's usually considered bad form to make your
model "too smart" about things - it should worry about business logic
and leave the integration details to the controllers. If, however, you
-find that it does not make sense at all to use an auxillary controller
+find that it does not make sense at all to use an auxiliary controller
around the model, and the model's need to access C<$c> cannot be
sidestepped, there exists a power tool called L</ACCEPT_CONTEXT>.
use base qw/Catalyst::Controller/;
- sub login : Path("login") { }
+ sub sign_in : Path("sign-in") { }
sub new_password : Path("new-password") { }
- sub logout : Path("logout") { }
+ sub sign_out : Path("sign-out") { }
package MyApp::Controller::Catalog;
model or view code. Instead you use the C<ACCEPT_CONTEXT> subroutine
to grab the bits of the context object that you need, and provide
accessors to them in the model. This ensures that C<$c> is only in
-scope where it is neaded which reduces maintenance and debugging
+scope where it is needed which reduces maintenance and debugging
headaches. So, if for example you needed two
L<Catalyst::Model::DBIC::Schema> models in the same Catalyst model
code, you might do something like this:
found, and automatically call the actions it finds that match the
circumstances of the request.
-The URL (for example http://localhost.3000/foo/bar) consists of two
+The URL (for example C<http://localhost:3000/foo/bar>) consists of two
parts, the base, describing how to connect to the server
-(http://localhost:3000/ in this example) and the path, which the
-server uses to decide what to return (foo/bar). Please note that the
+(C<http://localhost:3000/> in this example) and the path, which the
+server uses to decide what to return (C<foo/bar>). Please note that the
trailing slash after the hostname[:port] always belongs to base and
not to the path. Catalyst uses only the path part when trying to find
actions to process.
=item * B<Overriding the namespace>
-Note that __PACKAGE__->config->{namespace} can be used to override the
+Note that C<< __PACKAGE__->config->(namespace => ... ) >> can be used to override the
current namespace when matching. So:
package MyApp::Controller::Example;
would normally use 'example' as its namespace for matching, but if
this is specially overridden with
- __PACKAGE__->config->{namespace}='thing';
+ __PACKAGE__->config( namespace => 'thing' );
it matches using the namespace 'thing' instead.
-=item * B<Application Wide Actions>
+=item * B<Application-Wide Actions>
MyApp::Controller::Root, as created by the catalyst.pl script, will
typically contain actions which are called for the top level of the
-application (e.g. http://localhost:3000/ ):
+application (e.g. C<http://localhost:3000/>):
package MyApp::Controller::Root;
use base 'Catalyst::Controller';
+
# Sets the actions in this controller to be registered with no prefix
# so they function identically to actions created in MyApp.pm
- __PACKAGE__->config->{namespace} = '';
+
+ __PACKAGE__->config( namespace => '');
+
sub default : Path {
my ( $self, $context ) = @_;
$context->response->status(404);
$context->response->body('404 not found');
}
+
1;
The code
- __PACKAGE__->config->{namespace} = '';
+ __PACKAGE__->config( namespace => '' );
makes the controller act as if its namespace is empty. As you'll see
-below, an empty namespace makes many of the URL-matching attributes,
-such as :Path, :Local and :Global matches, match at the start of the
-URL path.
+below, an empty namespace makes many of the URL-matching attributes, such
+as :Path and :Local match at the start of the URL path (i.e. the
+application root).
=back
package MyApp::Controller::My::Controller;
sub foo : Local { }
-Matches any URL beginning with> http://localhost:3000/my/controller/foo. The namespace and
+Matches any URL beginning with> C<http://localhost:3000/my/controller/foo>. The namespace and
subroutine name together determine the path.
-=item * Namespace-level (C<:Global>)
+=item * Root-level (C<:Global>)
package MyApp::Controller::Foo;
- sub foo : Global { }
-Matches http://localhost:3000/foo - that is, the action is mapped
-directly to the controller namespace, ignoring the function name.
+ sub bar : Global {
+ my ($self, $c) = @_;
+ $c->res->body(
+ $c->res->body('sub bar in Controller::Foo triggered on a request for '
+ . $c->req->uri));
+ }
-C<:Global> is equivalent C<:Local> one level higher in
-the namespace.
+1;
- package MyApp::Controller::Root;
- __PACKAGE__->config->{namespace}='';
- sub foo : Local { }
+Matches C<http://localhost:3000/bar> - that is, the action is mapped
+directly to the method name, ignoring the controller namespace.
+
+C<:Global> always matches from the application root: it is simply
+shorthand for C<:Path('/methodname')>. C<:Local> is shorthand for
+C<:Path('methodname')>, which takes the controller namespace as described
+above.
-Use whichever makes the most sense for your application.
+Usage of the C<Global> handler is rare in all but very old Catalyst
+applications (e.g. before Catalyst 5.7). The use cases where C<Global>
+used to make sense are now largely replaced by the C<Chained> dispatch
+type, or by empty C<Path> declarations on an controller action. C<Global>
+is still included in Catalyst for backwards compatibility, although
+legitimate use-cases for it may still exist.
=item * Changing handler behaviour: eating arguments (C<:Args>)
-Args is not an action type per se, but an action modifier - it adds a
+C<:Args> is not an action type per se, but an action modifier - it adds a
match restriction to any action it's provided to, additionally
requiring as many path parts as are specified for the action to be
matched. For example, in MyApp::Controller::Foo,
to only match URLs starting /foo/bar/* - with one additional path
element required after 'bar'.
-NOTE that adding C<:Args(0)> and missing out :Args completely are B<not>
+NOTE that adding C<:Args(0)> and omitting C<:Args> are B<not>
the same thing.
C<:Args(0)> means that no arguments are taken. Thus, the URL and path must
match precisely.
-No :Args at all means that B<any number> of arguments are taken. Thus, any
-URL that B<starts with> the controller's path will match.
+No C<:Args> at all means that B<any number> of arguments are taken. Thus, any
+URL that B<starts with> the controller's path will match. Obviously, this means
+you cannot chain from an action that does not specify args, as the next action
+in the chain will be swallowed as an arg to the first!
=item * Literal match (C<:Path>)
C<Path> actions without a leading forward slash match a specified path
relative to their current namespace. This example matches URLs
-starting http://localhost:3000/my/controller/foo/bar :
+starting with C<http://localhost:3000/my/controller/foo/bar>:
package MyApp::Controller::My::Controller;
sub bar : Path('foo/bar') { }
package MyApp::Controller::My::Controller;
sub bar : Path('/foo/bar') { }
-This matches URLs beginning http://localhost:3000/foo/bar.
+This matches URLs beginning with C<http://localhost:3000/foo/bar>.
Empty C<Path> definitions match on the namespace only, exactly like
C<:Global>.
package MyApp::Controller::My::Controller;
sub bar : Path { }
-The above code matches http://localhost:3000/my/controller.
+The above code matches C<http://localhost:3000/my/controller>.
Actions with the C<:Local> attribute are similarly equivalent to
C<:Path('action_name')>:
sub foo : Path('foo') { }
-=item * Pattern-match (C<:Regex> and C<:LocalRegex>)
+=item * Pattern match (C<:Regex> and C<:LocalRegex>)
+
+B<Status: deprecated.> Use Chained methods or other techniques.
+If you really depend on this, install the standalone
+L<Catalyst::DispatchType::Regex> distribution.
package MyApp::Controller::My::Controller;
sub bar : Regex('^item(\d+)/order(\d+)$') { }
This matches any URL that matches the pattern in the action key, e.g.
-http://localhost:3000/item23/order42. The '' around the regexp is
+C<http://localhost:3000/item23/order42>. The '' around the regexp is
optional, but perltidy likes it. :)
C<:Regex> matches act globally, i.e. without reference to the namespace
from which they are called. So the above will B<not> match
-http://localhost:3000/my/controller/item23/order42 - use a
+C<http://localhost:3000/my/controller/item23/order42> - use a
C<:LocalRegex> action instead.
package MyApp::Controller::My::Controller;
C<:LocalRegex> actions act locally, i.e. the namespace is matched
first. The above example would match urls like
-http://localhost:3000/my/controller/widget23.
+C<http://localhost:3000/my/controller/widget23>.
If you omit the "C<^>" from either sort of regex, then it will match any depth
from the base path:
sub bar : LocalRegex('widget(\d+)$') { }
This differs from the previous example in that it will match
-http://localhost:3000/my/controller/foo/widget23 - and a number of
+C<http://localhost:3000/my/controller/foo/widget23> - and a number of
other paths.
For both C<:LocalRegex> and C<:Regex> actions, if you use capturing
sub auto : Private { }
C<auto>, however, doesn't override like this: providing they exist,
-C<MyApp::auto>, C<MyApp::Controller::Catalog::auto> and
+C<MyApp::Controller::Root::auto>, C<MyApp::Controller::Catalog::auto> and
C<MyApp::Catalog::Order::auto> would be called in turn.
Here are some examples of the order in which the various built-ins
If you don't want or need these features then it's perfectly acceptable
(and faster) to do something like this:
-sub hello : Global {
- my ( $self, $c ) = @_;
- $c->stash->{message} = 'Hello World!';
- $self->check_message( $c, 'test1' );
-}
-
-sub check_message {
- my ( $self, $c, $first_argument ) = @_;
- # do something...
-}
+ sub hello : Global {
+ my ( $self, $c ) = @_;
+ $c->stash->{message} = 'Hello World!';
+ $self->check_message( $c, 'test1' );
+ }
+
+ sub check_message {
+ my ( $self, $c, $first_argument ) = @_;
+ # do something...
+ }
Note that C<forward> returns to the calling action and continues
processing after the action finishes. If you want all further processing
comprehensive test scripts, L<Test::WWW::Mechanize::Catalyst> is an
invaluable tool.
-For more testing ideas, see L<Catalyst::Manual::Tutorial::Testing>.
+For more testing ideas, see L<Catalyst::Manual::Tutorial::08_Testing>.
Have fun!