features of how Catalyst works and shows how to get a simple application
up and running quickly. For an introduction (without code) to Catalyst
itself, and why you should be using it, see L<Catalyst::Manual::About>.
+For a systematic step-by-step introduction to writing an application
+with Catalyst, see L<Catalyst::Manual::Tutorial>.
=head2 What is Catalyst?
Catalyst is an elegant web application framework, extremely flexible yet
extremely simple. It's similar to Ruby on Rails, Spring (Java), and
-L<Maypole>, upon which it was originally based.
+L<Maypole>, upon which it was originally based. Its most important
+design philosphy 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. Under Catalyst, it is always possible to do things in a
+different way. However, this does mean that it is always possible to do
+things in a different way. Other web frameworks are simpler to use and
+easy to get up and running, 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.
=head3 MVC
=item * B<Model>
Access and modify content (data). L<DBIx::Class>, L<Class::DBI>,
-L<Plucene>, L<Net::LDAP>...
+L<Xapian>, L<Net::LDAP>...
=item * B<View>
);
1;
+In older versions of Catalyst, the application class was where you put
+global actions. However, as of version 5.66, the recommended practice is
+to place such actions in a special Root controller (see #####, below),
+to avoid namespace collisions.
+
=over 4
=item * B<name>
whatever you need. You can access them anywhere in your application via
C<$context-E<gt>config-E<gt>{$param_name}>.
+###### We need a short section on configuration here.
+
=head3 Context
Catalyst automatically blesses a Context object into your application
=head3 Actions
-
-
A Catalyst controller is defined by its actions. An action is a
subroutine with a special attribute. You've already seen some examples
of actions in this document. The URL (for example
=item * B<Application Wide Actions>
Actions which are called at the root level of the application
-(e.g. http:///localhost:3000/ ) go in MyApp::Controller::Root, like
+(e.g. http://localhost:3000/ ) go in MyApp::Controller::Root, like
this:
package MyApp::Controller::Root;
}
1;
-
=back
-For most applications, Catalyst requires you to define only one config
-parameter:
-
=head4 Action types
Catalyst supports several types of actions:
arguments at the end of your URL, you must use regex action keys. See
L</URL Path Handling> below.
+=item * B<Chained>
+
+The C<Chained> attribute allows you to chain public path parts together
+by their private names. A chain part's path can be specified with C<PathPart>
+and can be declared to expect an arbitrary number of arguments. The endpoint
+of the chain specifies how many arguments it gets through the C<Args>
+attribute. C<:Args(0)> would be none at all, C<:Args> without an integer
+would be unlimited. The path parts that aren't endpoints are using
+C<CaptureArgs> to specify how many parameters they expect to receive. As an
+example setup:
+
+ package MyApp::Controller::Greeting;
+ use base qw/ Catalyst::Controller /;
+
+ # this is the beginning of our chain
+ sub hello : PathPart('hello') Chained('/') CaptureArgs(1) {
+ my ( $self, $c, $integer ) = @_;
+ $c->stash->{ message } = "Hello ";
+ $c->stash->{ arg_sum } = $integer;
+ }
+
+ # this is our endpoint, because it has no :CaptureArgs
+ sub world : PathPart('world') Chained('hello') Args(1) {
+ my ( $self, $c, $integer ) = @_;
+ $c->stash->{ message } .= "World!";
+ $c->stash->{ arg_sum } += $integer;
+
+ $c->response->body( join "<br/>\n" =>
+ $c->stash->{ message }, $c->stash->{ arg_sum } );
+ }
+
+The debug output provides a separate table for chained actions, showing
+the whole chain as it would match and the actions it contains. Here's
+an example of the startup output with our actions above:
+
+ ...
+ [debug] Loaded Path Part actions:
+ .-----------------------+------------------------------.
+ | Path Spec | Private |
+ +-----------------------+------------------------------+
+ | /hello/*/world/* | /greeting/hello (1) |
+ | | => /greeting/world |
+ '-----------------------+------------------------------'
+ ...
+
+As you can see, Catalyst only deals with chains as whole path and
+builds one for each endpoint, which are the actions with C<:Chained>
+but without C<:CaptureArgs>.
+
+Let's assume this application gets a request at the path
+C</hello/23/world/12>, what happens then? First, Catalyst will dispatch
+to the C<hello> action and pass the value C<23> as argument to it after
+the context. It does so because we have previously used C<:CaptureArgs(1)>
+to declare that it has one path part after itself as it's argument. We
+told Catalyst that this is the beginning of the chain by specifying
+C<:Chained('/')>. Also note that instead of saying C<:PathPart('hello')>
+we could also just have said C<:PathPart>, as it defaults to the name of
+the action.
+
+After C<hello> has run, Catalyst goes on to dispatch to the C<world>
+action. This is the last action to be called, as Catalyst knows this
+is an endpoint because we specified no C<:CaptureArgs> attribute. Nevertheless
+we specify that this action expects an argument, but at this point we're
+using C<:Args(1)> to do that. We could also have said C<:Args> or leave
+it out alltogether, which would mean this action gets all arguments that
+are there. This action's C<:Chained> attribute says C<hello> and tells
+Catalyst that the C<hello> action in the current controller is it's
+parent.
+
+With this we have built a chain consisting of two public path parts.
+C<hello> captures one part of the path as it's argument, and also specifies
+the path root as it's parent. So this part is C</hello/$arg>. The next part
+is the endpoint C<world>, expecting one argument. It sums up to the path
+part C<world/$arg>. This leads to a complete chain of
+C</hello/$arg/world/$arg> which is matched against the requested paths.
+
+This example application would, if run and called by e.g.
+C</hello/23/world/12>, set the stash value C<message> to C<Hello > and
+the value C<arg_sum> to C<23>. The C<world> action would then append
+C<World!> to C<message> and add C<12> to the stash's C<arg_sum> value.
+For the sake of simplicity no view is shown. Instead we just put the
+values of the stash into our body. So the output would look like:
+
+ Hello World!
+ 35
+
+And our test server would've given us this debugging output for the
+request:
+
+ ...
+ [debug] "GET" request for "hello/23/world/12" from "127.0.0.1"
+ [debug] Path is "/greeting/world"
+ [debug] Arguments are "12"
+ [info] Request took 0.164113s (6.093/s)
+ .------------------------------------------+-----------.
+ | Action | Time |
+ +------------------------------------------+-----------+
+ | /greeting/hello | 0.000029s |
+ | /greeting/world | 0.000024s |
+ '------------------------------------------+-----------'
+ ...
+
+What would be common usecases of this dispatching technique? It gives the
+possibility to split up logic that contains steps that each depend on each
+other. An example would be, for example, a wiki path like
+C</wiki/FooBarPage/rev/23/view>. This chain can be easily built with
+these actions:
+
+ sub wiki : PathPart('wiki') Chained('/') CaptureArgs(1) {
+ my ( $self, $c, $page_name ) = @_;
+ # load the page named $page_name and put the object
+ # into the stash
+ }
+
+ sub rev : PathPart('rev') Chained('wiki') CaptureArgs(1) {
+ my ( $self, $c, $revision_id ) = @_;
+ # use the page object in the stash to get at it's
+ # revision with number $revision_id
+ }
+
+ sub view : PathPart Chained('rev') Args(0) {
+ my ( $self, $c ) = @_;
+ # display the revision in our stash. An other option
+ # would be to forward a compatible object to the action
+ # that displays the default wiki pages, unless we want
+ # a different interface here, for example restore
+ # functionality.
+ }
+
+It would now be possible to add other endpoints. For example C<restore> to
+restore this specific revision as current state.
+
+Also, you of course don't have to put all the chained actions in one
+controller. The specification of the parent through C<:Chained> also takes
+an absolute action path as it's argument. Just specify it with a leading
+C</>.
+
+If you want, for example, to have actions for the public paths
+C</foo/12/edit> and C</foo/12>, just specify two actions with
+C<:PathPart('foo')> and C<:Chained('/')>. The handler for the former
+path needs a C<:CaptureArgs(1)> attribute and a endpoint with
+C<:PathPart('edit')> and C<:Chained('foo')>. For the latter path give
+the action just a C<:Args(1)> to mark it as endpoint. This sums up to
+this debugging output:
+
+ ...
+ [debug] Loaded Path Part actions:
+ .-----------------------+------------------------------.
+ | Path Spec | Private |
+ +-----------------------+------------------------------+
+ | /foo/* | /controller/foo_view |
+ | /foo/*/edit | /controller/foo_load (1) |
+ | | => /controller/edit |
+ '-----------------------+------------------------------'
+ ...
+
+Here's a more detailed specification of the attributes belonging to
+C<:Chained>:
+
+=over 8
+
+=item PathPart
+
+Sets the name of this part of the chain. If it is specified without
+arguments, it takes the name of the action as default. So basically
+C<sub foo :PathPart> and C<sub foo :PathPart('foo')> are identical.
+This can also contain slashes to bind to a deeper level. An action
+with C<sub bar :PathPart('foo/bar') :Chained('/')> would bind to
+C</foo/bar/...>. If you don't specify C<:PathPart> it has the same
+effect as using C<:PathPart>, it would default to the action name.
+
+=item Chained
+
+Has to be specified for every child in the chain. Possible values are
+absolute and relative private action paths, with the relatives pointing
+to the current controller, or a single slash C</> to tell Catalyst that
+this is the root of a chain. The attribute C<:Chained> without aguments
+also defaults to the C</> behaviour.
+
+Due to the fact that you can specify an absolute path to the parent
+action, it doesn't matter to Catalyst where that parent is located. So,
+if your design requests it, you can redispatch a chain through every
+controller or namespace you want.
+
+Another interesting possibility gives C<:Chained('.')>, which chains
+itself to an action with the path of the current controllers namespace.
+For example:
+
+ # in MyApp::Controller::Foo
+ sub bar : Chained CaptureArgs(1) { ... }
+
+ # in MyApp::Controller::Foo::Bar
+ sub baz : Chained('.') Args(1) { ... }
+
+This builds up a chain like C</bar/*/baz/*>. The specification of C<.>
+as argument to Chained here chains the C<baz> action to an action with
+the path of the current controller namespace, namely C</foo/bar>. That
+action chains directly to C</>, so the above chain comes out as end
+product.
+
+=item CaptureArgs
+
+Also has to be specified for every part of the chain that is not an
+endpoint. With this attribute Catalyst knows how many of the following
+parts of the path (separated by C</>) this action wants to captures as
+it's arguments. If it doesn't expect any, just specify C<:CaptureArgs(0)>.
+The captures get passed to the action's C<@_> right after the context,
+but you can also find them as array reference in
+C<$c-E<gt>request-E<gt>captures-E<gt>[$level]>. The C<$level> is the
+level of the action in the chain that captured the parts of the path.
+
+An action that is part of a chain (read: that has a C<:Chained> attribute)
+but has no C<:CaptureArgs> attribute is treated by Catalyst as a chain end.
+
+=item Args
+
+By default, endpoints receive the rest of the arguments in the path. You
+can tell Catalyst through C<:Args> explicitly how many arguments your
+endpoint expects, just like you can with C<:CaptureArgs>. Note that this
+also influences if this chain is invoked on a request. A chain with an
+endpoint specifying one argument will only match if exactly one argument
+exists in the path.
+
+You can specify an exact number of arguments like C<:Args(3)>, including
+C<0>. If you just say C<:Args> without any arguments, it is the same as
+leaving it out alltogether: The chain is matched independent of the number
+of path parts after the endpoint.
+
+Just like with C<:CaptureArgs>, the arguments get passed to the action in
+C<@_> after the context object. They can also be reached through
+C<$c-E<gt>request-E<gt>arguments>.
+
+=back
+
+Note that the list of C<auto> actions called depends on the private path
+of the endpoint of the chain, not on the chained actions way. The C<auto>
+actions will be run before the chain dispatching begins. In every other
+aspect, C<auto> actions behave as documented.
+
+The C<forward>ing to other actions does just what you would expect. But if
+you C<detach> out of a chain, the rest of the chain will not get called
+after the C<detach> returned.
+
=item * B<Top-level> (B<Global>)
package MyApp::Controller::Foo;
$c->res->body( $c->stash->{message} );
}
-A C<forward> does not create a new request, so your request
-object (C<$c-E<gt>req>) will remain unchanged. This is a
-key difference between using C<forward> and issuing a
-redirect.
+A C<forward> does not create a new request, so your request object
+(C<$c-E<gt>req>) will remain unchanged. This is a key difference between
+using C<forward> and issuing a redirect.
You can pass new arguments to a C<forward> by adding them
in an anonymous array. In this case C<$c-E<gt>req-E<gt>args>
Controllers. Catalyst automatically discovers and instantiates them
when you call C<setup> in the main application. All you need to do is
put them in directories named for each Component type. Notice that you
-can use some very terse aliases for each one.
+can use a terse alias for each one.
=over 4
=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, 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
=back
-From a style perspective usually it's bad 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 around the model, and the model's need to access
-C<$c> cannot be sidestepped, there exists a power tool called C<ACCEPT_CONTEXT>.
+From a style perspective usually it's bad 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 around the
+model, and the model's need to access C<$c> cannot be sidestepped, there
+exists a power tool called C<ACCEPT_CONTEXT>.
#### editor note: this part is "generic" - it also applies to views and
#### controllers.
=head3 ACCEPT_CONTEXT
-Whenever you call $c->component("Foo") you get back an object - the instance of
-the model. If the component supports the C<ACCEPT_CONTEXT> method instead of
-returning the model itself, the return value of
-C<< $model->ACCEPT_CONTEXT( $c ) >> will be used.
+Whenever you call $c->component("Foo") you get back an object - the
+instance of the model. If the component supports the C<ACCEPT_CONTEXT>
+method instead of returning the model itself, the return value of C<<
+$model->ACCEPT_CONTEXT( $c ) >> will be used.
This means that whenever your model/view/controller needs to talk to C<$c> it
gets a chance to do this when it's needed.
with the context object set, or it will return a thin wrapper that contains
C<$c> and delegates to the per-application model object.
-A typicall C<ACCEPT_CONTEXT> method could look like this:
+A typical C<ACCEPT_CONTEXT> method could look like this:
sub ACCEPT_CONTEXT {
my ( $self, $c, @extra_arguments ) = @_;
}
-
=head3 Testing
-Catalyst has a built-in http server for testing! (Later, you can easily
-use a more powerful server, e.g. Apache/mod_perl, in a production
-environment.)
+Catalyst has a built-in http server for testing. (Later, you can easily
+use a more powerful server, e.g. Apache/mod_perl or FastCGI, in a
+production environment.)
Start your application on the command line...