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
=head3 Install
-Installation of Catalyst can be a time-consuming effort, due to its
-large number of dependencies. Although most of the frustrations
-associated with this are now ironed out and a simple C<cpan
-Catalyst::Devel> or C<cpan Catalyst::Runtime> are now usually
-straightforward, if you still have problems, you can use use Matt
-Trout's C<cat-install> script, from
-L<http://www.shadowcatsystems.co.uk/static/cat-install>, and then
-install L<Catalyst::Devel>.
+Installation of Catalyst should be straightforward:
- # perl cat-install
+ # perl -MCPAN -e 'install Catalyst::Runtime'
# perl -MCPAN -e 'install Catalyst::Devel'
=head3 Setup
many L</Models>, L</Views>, and L</Controllers> as you like. As discussed
previously, the general idea is that the View is responsible for the
output of data to the user (typically via a web browser, but a View can
-also generate PDFs or e-mails, for example); the Model is responsible
+also generate PDFs or e-mails, for example); the Model is responsible
for providing data (typically from a relational database); and the
Controller is responsible for interacting with the user and deciding
how user input determines what actions the application takes.
In the world of MVC, there are frequent discussions and disagreements
about the nature of each element - whether certain types of logic
belong in the Model or the Controller, etc. Catalyst's flexibility
-means that this decision is entirely up to you, the programmer;
+means that this decision is entirely up to you, the programmer;
Catalyst doesn't enforce anything. See L<Catalyst::Manual::About> for
a general discussion of these issues.
common class methods like C<config> and C<new> (constructor).
package MyApp::Controller::Catalog;
+ use Moose;
+ use namespace::autoclean;
- use strict;
- use base 'Catalyst::Controller';
+ BEGIN { extends 'Catalyst::Controller' }
__PACKAGE__->config( foo => 'bar' );
=over 4
-=item * B<MyApp/Model/>
+=item * B<MyApp/Model/>
=item * B<MyApp/M/>
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, we now recommend
-the use of the full names.
+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
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.
sub view : Global {
my ( $self, $c, $id ) = @_;
-
+
$c->stash->{item} = $c->model('MyModel::Foo')->find($id);
}
1;
-
+
sub end : Private {
my ( $self, $c ) = @_;
-
+
$c->stash->{template} ||= 'index.tt';
$c->forward( $c->view('TT') );
}
# in a Controller
sub list : Local {
my ( $self, $c ) = @_;
-
+
$c->stash->{template} = 'list.tt';
-
+
use Some::Outside::Database::Module;
my @records = Some::Outside::Database::Module->search({
artist => 'Led Zeppelin',
});
-
+
$c->stash->{records} = \@records;
}
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 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
=item * B<Overriding the namespace>
-Note that __PACKAGE__->config->{namespace} can be used to override the
+Note that I<< __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.
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
=item * Namespace-prefixed (C<:Local>)
- package MyApp::Controller::My::Controller;
+ package MyApp::Controller::My::Controller;
sub foo : Local { }
Matches any URL beginning with> 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 http://localhost:3000/bar - that is, the action is mapped
+directly to the method name, ignoring the controller namespace.
-Use whichever makes the most sense for your application.
+C<:Global> always matches from the application root: it is simply
+shorthandfor C<:Path('/methodname')>. C<:Local> is shorthand for
+C<:Path('methodname')>, which takes the controller namespace as described
+above.
-=item * Changing handler behaviour: adding arguments (C<:Args>)
+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
match restriction to any action it's provided to, additionally
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>
+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. 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 match things starting with a precise specified path,
Actions with the C<:Local> attribute are similarly equivalent to
C<:Path('action_name')>:
- sub foo : Local { }
+ sub foo : Local { }
-is equivalent to
+is equivalent to
sub foo : Path('foo') { }
=item * Pattern-match (C<:Regex> and C<:LocalRegex>)
-
+
package MyApp::Controller::My::Controller;
sub bar : Regex('^item(\d+)/order(\d+)$') { }
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
that URL.
B<Note:> Looking at it another way, C<auto> actions have to return a
-true value to continue processing!
+true value to continue processing!
=head4 URL Path Handling
So Catalyst would never mistakenly dispatch the first two URLs to the
'^foo$' action.
-If a Regex or LocalRegex action doesn't use the '$' anchor, the action will
-still match a URL containing arguments; however the arguments won't be
+If a Regex or LocalRegex action doesn't use the '$' anchor, the action will
+still match a URL containing arguments; however the arguments won't be
available via C<@_>, because the Regex will 'eat' them.
Beware! If you write two matchers, that match the same path, with the
my $current_page = $c->req->param('page') || 1;
# multiple values for single parameter name
- my @values = $c->req->param('scrolling_list');
+ my @values = $c->req->param('scrolling_list');
# DFV requires a CGI.pm-like input hash
my $results = Data::FormValidator->check($c->req->params, \%dfv_profile);
# now $c->req->args is back to what it was before
}
- sub check_message : Private {
- my ( $self, $c ) = @_;
- my $first_argument = $c->req->args->[0]; # now = 'test1'
+ sub check_message : Action {
+ my ( $self, $c, $first_argument ) = @_;
+ my $also_first_argument = $c->req->args->[0]; # now = 'test1'
# do something...
}
$c->forward('/my/controller/action');
$c->forward('/default'); # calls default in main application
-Here are some examples of how to forward to classes and methods.
+You can also forward to classes and methods.
sub hello : Global {
my ( $self, $c ) = @_;
- $c->forward(qw/MyApp::Model::Hello say_hello/);
+ $c->forward(qw/MyApp::View:Hello say_hello/);
}
sub bye : Global {
$c->forward('MyApp::Model::Hello'); # no method: will try 'process'
}
- package MyApp::Model::Hello;
+ package MyApp::View::Hello;
sub say_hello {
my ( $self, $c ) = @_;
$c->res->body('Goodbye World!');
}
+This mechanism is used by L<Catalyst::Action::RenderView> to forward
+to the C<process> method in a view class.
+
+It should be noted that whilst forward is useful, it is not the only way
+of calling other code in Catalyst. Forward just gives you stats in the debug
+screen, wraps the code you're calling in an exception handler and localises
+C<< $c->request->args >>.
+
+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...
+ }
+
Note that C<forward> returns to the calling action and continues
processing after the action finishes. If you want all further processing
in the calling action to stop, use C<detach> instead, which will execute
Catalyst will automatically try to call process() if you omit the
method.
-
=head3 Testing
Catalyst has a built-in http server for testing or local
http://dev.catalystframework.org/wiki/faq
-=head1 AUTHOR
+=head1 AUTHORS
-Sebastian Riedel, C<sri@oook.de>
-David Naughton, C<naughton@umn.edu>
-Marcus Ramberg, C<mramberg@cpan.org>
-Jesse Sheidlower, C<jester@panix.com>
-Danijel Milicevic, C<me@danijel.de>
-Kieren Diment, C<kd@totaldatasolution.com>
-Yuval Kogman, C<nothingmuch@woobling.org>
+Catalyst Contributors, see Catalyst.pm
=head1 COPYRIGHT
-This program is free software. You can redistribute it and/or modify it
-under the same terms as Perl itself.
+This library is free software. You can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut