X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FIntro.pod;h=9eaaf37077d9708d91d2272d5d4dc8d044fb33b2;hp=5aff62131154c45fe639333da9ca2eefcae3c240;hb=54550e133a0ef80726b4fac78299b907f5f6948d;hpb=cb93c9d7a46377666f9593736dcb87fad8f9d82e diff --git a/lib/Catalyst/Manual/Intro.pod b/lib/Catalyst/Manual/Intro.pod index 5aff621..9eaaf37 100644 --- a/lib/Catalyst/Manual/Intro.pod +++ b/lib/Catalyst/Manual/Intro.pod @@ -14,17 +14,17 @@ with Catalyst, see L. =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, 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. However, this does mean that it is always possible to -do things in a different way. Other web frameworks are B -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 tasks -than other web frameworks. +yet extremely simple. It's similar to Ruby on Rails, Spring (Java), and +L, 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. However, this does mean that it is always +possible to do things in a different way. Other web frameworks are +I 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 +tasks than other web frameworks. =head3 MVC @@ -97,17 +97,30 @@ doesn't require mod_rewrite or class and method names in URLs. With Catalyst you register your actions and address them directly. For example: - sub hello : Global { + sub hello : Local { my ( $self, $context ) = @_; $context->response->body('Hello World!'); } Now http://localhost:3000/hello prints "Hello World!". +Note that actions with the C< :Global > attribute are equivalent to +using a C<:Path('action_name') > attribute, so our action could be +equivalently: + + sub hi : Path('hello') { + my ( $self, $context ) = @_; + $context->response->body('Hello World!'); + } + + =item * B -Use L or L. Other -engines are also available. +Use L or L. Another +interesting engine is L - available from CPAN +separately - which will turn the built server into a fully fledged production +ready server (although you'll probably want to run it behind a front end proxy +if you end up using it). =back @@ -158,13 +171,9 @@ running, using the helper scripts described above. =head3 Install -Installation of Catalyst can be a time-consuming and frustrating -effort, due to its large number of dependencies. The easiest way -to get up and running is to use Matt Trout's C -script, from L, -and then install L. +Installation of Catalyst should be straightforward: - # perl cat-install + # perl -MCPAN -e 'install Catalyst::Runtime' # perl -MCPAN -e 'install Catalyst::Devel' =head3 Setup @@ -174,6 +183,16 @@ and then install L. $ cd MyApp $ script/myapp_create.pl controller Library::Login +=head4 Frank Speiser's Amazon EC2 Catalyst SDK + +There are currently two flavors of publicly available Amazon Machine +Images (AMI) that include all the elements you'd need to begin +developing in a fully functional Catalyst environment within +minutes. See +L for +more details. + + =head3 Run $ script/myapp_server.pl @@ -204,7 +223,7 @@ Catalyst has an uncommonly flexible component system. You can define as many L, L, and L 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. @@ -212,18 +231,20 @@ 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 for a general discussion of these issues. -All components must inherit from L, which provides a -simple class structure and some common class methods like C and -C (constructor). +Model, View and Controller components must inherit from L, +L and L, respectively. These, in turn, inherit +from L which provides a simple class structure and some +common class methods like C and C (constructor). package MyApp::Controller::Catalog; + use Moose; + use namespace::autoclean; - use strict; - use base 'Catalyst::Base'; + BEGIN { extends 'Catalyst::Controller' } __PACKAGE__->config( foo => 'bar' ); @@ -237,7 +258,7 @@ short alias for each one. =over 4 -=item * B +=item * B =item * B @@ -253,8 +274,8 @@ short alias for each one. In older versions of Catalyst, the recommended practice (and the one automatically created by helper scripts) was to name the directories -C, C, and C. Though these still work, we now recommend -the use of the full names. +C, C, and C. Though these still work, they are deprecated +and we now recommend the use of the full names. =head4 Views @@ -330,15 +351,15 @@ But first, we need a database. INSERT INTO foo (data) VALUES ('TEST!'); - % sqlite /tmp/myapp.db < myapp.sql + % sqlite3 /tmp/myapp.db < myapp.sql Now we can create a DBIC::Schema model for this database. script/myapp_create.pl model MyModel DBIC::Schema MySchema create=static 'dbi:SQLite:/tmp/myapp.db' -L automatically loads table layouts and -relationships, and converts them into a static schema definition C, -which you can edit later. +L can automatically load table layouts and +relationships, and convert them into a static schema definition +C, which you can edit later. Use the stash to pass data to your templates. @@ -346,15 +367,15 @@ We add the following to MyApp/Controller/Root.pm 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') ); } @@ -369,14 +390,14 @@ can always call an outside module that serves as your Model: # 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; } @@ -502,27 +523,54 @@ instance of the model. If the component supports the C 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. +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. A typical C method will either clone the model and return one 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 typical C method could look like this: - - sub ACCEPT_CONTEXT { - my ( $self, $c, @extra_arguments ) = @_; - bless { %$self, c => $c }, ref($self); - } - -effectively treating $self as a B that gets a new parameter. -C<@extra_arguments> comes from any trailing arguments to -C<< $c->component( $bah, @extra_arguments ) >> (or C<< $c->model(...) >>, -C<< $c->view(...) >> etc). - -The life time of this value is B, and not per request. To make this -per request you can use the following technique: +Generally it's a bad idea to expose the context object (C<$c>) in your +model or view code. Instead you use the C 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 +headaches. So, if for example you needed two +L models in the same Catalyst model +code, you might do something like this: + + __PACKAGE__->mk_accessors(qw(model1_schema model2_schema)); + sub ACCEPT_CONTEXT { + my ( $self, $c, @extra_arguments ) = @_; + $self = bless({ %$self, + model1_schema => $c->model('Model1')->schema, + model2_schema => $c->model('Model2')->schema + }, ref($self)); + return $self; + } + +This effectively treats $self as a B that gets a new +parameter. C<@extra_arguments> comes from any trailing arguments to +C<< $c->component( $bah, @extra_arguments ) >> (or C<< $c->model(...) +>>, C<< $c->view(...) >> etc). + +In a subroutine in the model code, we can then do this: + + sub whatever { + my ($self) = @_; + my $schema1 = $self->model1_schema; + my $schema2 = $self->model2_schema; + ... + } + +Note that we still want the Catalyst models to be a thin wrapper +around classes that will work independently of the Catalyst +application to promote reusability of code. Here we might just want +to grab the $c->model('DB')->schema so as to get the connection +information from the Catalyst application's configuration for example. + +The life time of this value is B, and not per request. To +make this per request you can use the following technique: Add a field to C<$c>, like C. Then write your C method to look like this: @@ -540,6 +588,9 @@ C method to look like this: } } +For a similar technique to grab a new component instance on each +request, see L. + =head3 Application Class In addition to the Model, View, and Controller components, there's a @@ -549,9 +600,8 @@ configure your application, load plugins, and extend Catalyst. package MyApp; use strict; - use Catalyst qw/-Debug/; # Add other plugins here, e.g. - # for session support - + use parent qw/Catalyst/; + use Catalyst qw/-Debug ConfigLoader Static::Simple/; MyApp->config( name => 'My Application', @@ -629,7 +679,7 @@ information. $c->res->status(404); $c->res->redirect('http://oook.de'); -=item * L +=item * config $c->config $c->config->{root}; @@ -674,129 +724,252 @@ Catalyst-friendly session-handling tools. =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 -http://localhost.3000/foo/bar) consists of two parts, the base -(http://localhost:3000/ in this example) and the path (foo/bar). Please -note that the trailing slash after the hostname[:port] always belongs to -base and not to the action. +You've already seen some examples of actions in this document: +subroutines with C<:Path> and C<:Local> attributes attached. +Here, we explain what actions are and how these attributes affect +what's happening. + +When Catalyst processes a webpage request, it looks for actions to +take that will deal with the incoming request and produce a response +such as a webpage. You create these actions for your application by +writing subroutines within your controller and marking them with +special attributes. The attributes, the namespace, and the function +name determine when Catalyst will call the subroutine. + +These action subroutines call certain functions to say what response +the webserver will give to the web request. They can also tell +Catalyst to run other actions on the request (one example of this is +called forwarding the request; this is discussed later). + +Action subroutines must have a special attribute on to show that they +are actions - as well as marking when to call them, this shows that +they take a specific set of arguments and behave in a specific way. +At startup, Catalyst looks for all the actions in controllers, +registers them and creates L objects describing +them. When requests come in, Catalyst chooses which actions should be +called to handle the request. + +(Occasionally, you might use the action objects directly, but in +general, when we talk about actions, we're talking about the +subroutines in your application that do things to process a request.) + +You can choose one of several attributes for action subroutines; these +specify which requests are processed by that subroutine. Catalyst +will look at the URL it is processing, and the actions that it has +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 +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 +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. + +Depending on the type of action used, the URLs may match a combination +of the controller namespace, the arguments passed to the action +attribute, and the name of the subroutine. =over 4 +=item * B + +The namespace is a modified form of the component's class (package) +name. This modified class name excludes the parts that have a +pre-defined meaning in Catalyst ("MyApp::Controller" in the above +example), replaces "::" with "/", and converts the name to lower case. +See L for a full explanation of the pre-defined meaning +of Catalyst component class names. + +=item * B + +Note that __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'; + +it matches using the namespace 'thing' instead. + =item * B -Actions which are called at the root level of the application -(e.g. http://localhost:3000/ ) go in MyApp::Controller::Root, like -this: +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/ ): 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} = ''; - sub default : Private { + sub default : Path { my ( $self, $context ) = @_; - $context->response->body('Catalyst rocks!'); + $context->response->status(404); + $context->response->body('404 not found'); } 1; + +The code + + __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. + =back =head4 Action types -Catalyst supports several types of actions: +Catalyst supports several types of actions. These mainly correspond +to ways of matching a URL to an action subroutine. Internally, these +matching types are implemented by L-derived +classes; the documentation there can be helpful in seeing how they +work. + +They will all attempt to match the start of the path. The remainder +of the path is passed as arguments. =over 4 -=item * B (B actions) +=item * Namespace-prefixed (C<:Local>) + + 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 * 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. + +C<:Global> always matches from root: it is sugar for C<:Path('/methodname')>. +C<:Local> is simply sugar for C<:Path('methodname')>, which takes the package +namespace as described above. + + package MyApp::Controller::Root; + __PACKAGE__->config->{namespace}=''; + sub foo : Local { } + +Use whichever makes the most sense for your application. + +=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 +requiring as many path parts as are specified for the action to be +matched. For example, in MyApp::Controller::Foo, + + sub bar :Local + +would match any URL starting /foo/bar. To restrict this you can do + + sub bar :Local :Args(1) + +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 +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 of arguments are taken. Thus, any +URL that B 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 actions match things starting with a precise specified path, +and nothing else. + +C 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 : package MyApp::Controller::My::Controller; sub bar : Path('foo/bar') { } -Literal C actions will act relative to their current -namespace. The above example matches only -http://localhost:3000/my/controller/foo/bar. If you start your path with -a forward slash, it will match from the root. Example: +C actions B a leading slash ignore their namespace, and +match from the start of the URL path. Example: package MyApp::Controller::My::Controller; sub bar : Path('/foo/bar') { } -Matches only http://localhost:3000/foo/bar. +This matches URLs beginning http://localhost:3000/foo/bar. + +Empty C definitions match on the namespace only, exactly like +C<:Global>. package MyApp::Controller::My::Controller; sub bar : Path { } -By leaving the C definition empty, it will match on the namespace -root. The above code matches http://localhost:3000/my/controller. +The above code matches http://localhost:3000/my/controller. -=item * B +Actions with the C<:Local> attribute are similarly equivalent to +C<:Path('action_name')>: + + sub foo : Local { } +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+)$') { } -Matches any URL that matches the pattern in the action key, e.g. +This matches any URL that matches the pattern in the action key, e.g. http://localhost:3000/item23/order42. The '' around the regexp is optional, but perltidy likes it. :) -Regex matches act globally, i.e. without reference to the namespace from -which it is called, so that a C method in the -C namespace won't match any -form of C, C, C, or C unless you -explicitly put this in the regex. To achieve the above, you should -consider using a C action. - -=item * B +C<:Regex> matches act globally, i.e. without reference to the namespace +from which they are called. So the above will B match +http://localhost:3000/my/controller/item23/order42 - use a +C<:LocalRegex> action instead. + package MyApp::Controller::My::Controller; sub bar : LocalRegex('^widget(\d+)$') { } -LocalRegex actions act locally. If you were to use C in -C, the above example would match urls like -http://localhost:3000/catalog/widget23. +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. -If you omit the "C<^>" from your regex, then it will match any depth -from the controller and not immediately off of the controller name. The -following example differs from the above code in that it will match -http://localhost:3000/catalog/foo/widget23 as well. +If you omit the "C<^>" from either sort of regex, then it will match any depth +from the base path: package MyApp::Controller::Catalog; sub bar : LocalRegex('widget(\d+)$') { } -For both LocalRegex and Regex actions, if you use capturing parentheses -to extract values within the matching URL, those values are available in -the C<$c-Ereq-Ecaptures> array. In the above example, "widget23" -would capture "23" in the above example, and -C<$c-Ereq-Ecaptures-E[0]> would be "23". If you want to pass -arguments at the end of your URL, you must use regex action keys. See -L below. - -=item * B (B) - - package MyApp::Controller::Foo; - sub foo : Global { } - -Matches http://localhost:3000/foo. The function name is mapped -directly to the application base. You can provide an equivalent -function in this case by doing the following: +This differs from the previous example in that it will match +http://localhost:3000/my/controller/foo/widget23 - and a number of +other paths. - package MyApp::Controller::Root - sub foo : Local { } +For both C<:LocalRegex> and C<:Regex> actions, if you use capturing +parentheses to extract values within the matching URL, those values +are available in the C<$c-Ereq-Ecaptures> array. In the above +example, "widget23" would capture "23" in the above example, and +C<$c-Ereq-Ecaptures-E[0]> would be "23". If you want to +pass arguments at the end of your URL, you must use regex action +keys. See L below. -=item * B (B) - - package MyApp::Controller::My::Controller; - sub foo : Local { } - -Matches http://localhost:3000/my/controller/foo. - -This action type indicates that the matching URL must be prefixed with a -modified form of the component's class (package) name. This modified -class name excludes the parts that have a pre-defined meaning in -Catalyst ("MyApp::Controller" in the above example), replaces "::" with -"/", and converts the name to lower case. See L for a full -explanation of the pre-defined meaning of Catalyst component class -names. - -=item * B +=item * Chained handlers (C<:Chained>) Catalyst also provides a method to build and dispatch chains of actions, like @@ -811,116 +984,123 @@ like ... } -to handle a C path. For further information about this -dispatch type, please see L. +to handle a C path. Matching actions are called +one after another - C gets called and handed one path +element, then C gets called with another one. For further +information about this dispatch type, please see +L. =item * B sub foo : Private { } -Matches no URL, and cannot be executed by requesting a URL that -corresponds to the action key. Private actions can be executed only -inside a Catalyst application, by calling the C method: - - $c->forward('foo'); - -See L for a full explanation of C. Note that, as -discussed there, when forwarding from another component, you must use -the absolute path to the method, so that a private C method in your -C controller must, if called -from elsewhere, be reached with -C<$c-Eforward('/catalog/order/process/bar')>. +This will never match a URL - it provides a private action which can +be called programmatically from within Catalyst, but is never called +automatically due to the URL being requested. -=item * B - -Args is not an action type per se, but an action modifier - it adds a -match restriction to any action it's provided to, requiring only as many -path parts as are specified for the action to be valid - for example in -MyApp::Controller::Foo, +Catalyst's C<:Private> attribute is exclusive and doesn't work with other +attributes (so will not work combined with C<:Path> or C<:Chained> +attributes, for instance). - sub bar :Local - -would match any URL starting /foo/bar/. To restrict this you can do - - sub bar :Local :Args(1) +Private actions can only be executed explicitly from inside a Catalyst +application. You might do this in your controllers by calling +catalyst methods such as C or C to fire them: -to only match /foo/bar/*/ + $c->forward('foo'); + # or + $c->detach('foo'); + +See L for a full explanation of how you can pass +requests on to other actions. Note that, as discussed there, when +forwarding from another component, you must use the absolute path to +the method, so that a private C method in your +C controller must, if +called from elsewhere, be reached with +C<$c-Eforward('/catalog/order/process/bar')>. =back -B After seeing these examples, you probably wonder what the point -is of defining names for regex and path actions. Every public action is -also a private one, so you have one unified way of addressing components -in your Cs. +B After seeing these examples, you probably wonder what the +point is of defining subroutine names for regex and path +actions. However, every public action is also a private one with a +path corresponding to its namespace and subroutine name, so you have +one unified way of addressing components in your Cs. + +=head4 Built-in special actions -=head4 Built-in Private Actions +If present, the special actions C< index >, C< auto >, C, +C and C< default > are called at certain points in the request +cycle. In response to specific application states, Catalyst will automatically -call these built-in private actions in your application class: +call these built-in actions in your application class: =over 4 -=item * B +=item * B -Called when no other action matches. Could be used, for example, for -displaying a generic frontpage for the main app, or an error page for -individual controllers. +This is called when no other action matches. It could be used, for +example, for displaying a generic frontpage for the main app, or an +error page for individual controllers. B: in older Catalyst +applications you will see C which is roughly +speaking equivalent. -If C isn't acting how you would expect, look at using a -L C action (with an empty path string). The difference -is that C takes arguments relative from the namespace and -C I takes arguments relative from the root, regardless -of what controller it's in. Indeed, this is now the recommended way of -handling default situations; the C private controller should -be considered deprecated. -=item * B +=item * B -C is much like C except that it takes no arguments -and it is weighted slightly higher in the matching process. It is -useful as a static entry point to a controller, e.g. to have a static -welcome page. Note that it's also weighted higher than Path. +C is much like C except that it takes no arguments and +it is weighted slightly higher in the matching process. It is useful +as a static entry point to a controller, e.g. to have a static welcome +page. Note that it's also weighted higher than Path. Actually the sub +name C can be called anything you want. The sub attributes are +what determines the behaviour of the action. B: in older +Catalyst applications, you will see C used, which is +roughly speaking equivalent. =item * B -Called at the beginning of a request, before any matching actions are -called. +Called at the beginning of a request, once the controller that will +run has been identified, but before any URL-matching actions are +called. Catalyst will call the C function in the controller +which contains the action matching the URL. =item * B -Called at the end of a request, after all matching actions are called. +Called at the end of a request, after all URL-matching actions are called. +Catalyst will call the C function in the controller +which contains the action matching the URL. + +=item * B + +In addition to the normal built-in actions, you have a special action +for making chains, C. C actions will be run after any +C, but before your URL-matching action is processed. Unlike the other +built-ins, multiple C actions can be called; they will be +called in turn, starting with the application class and going through +to the most specific class. =back =head4 Built-in actions in controllers/autochaining - Package MyApp::Controller::Foo; + package MyApp::Controller::Foo; sub begin : Private { } - sub default : Private { } - sub auto : Private { } - -You can define built-in private actions within your controllers as -well. The actions will override the ones in less-specific controllers, -or your application class. In other words, for each of the three -built-in private actions, only one will be run in any request -cycle. Thus, if C exists, it will be -run in place of C if you're in the C namespace, -and C would override this in + sub default : Path { } + sub end : Path { } + +You can define built-in actions within your controllers as well as on +your application class. In other words, for each of the three built-in +actions above, only one will be run in any request cycle. Thus, if +C exists, it will be run in place +of C if you're in the C namespace, and +C would override this in turn. -=over 4 - -=item * B - -In addition to the normal built-in actions, you have a special action -for making chains, C. Such C actions will be run after any -C, but before your action is processed. Unlike the other -built-ins, C actions I override each other; they will be -called in turn, starting with the application class and going through to -the I specific class. I. + sub auto : Private { } -=back +C, however, doesn't override like this: providing they exist, +C, C and +C would be called in turn. Here are some examples of the order in which the various built-ins would be called: @@ -929,15 +1109,13 @@ would be called: =item for a request for C - MyApp::begin - MyApp::auto + MyApp::Controller::Foo::auto MyApp::Controller::Foo::default # in the absence of MyApp::Controller::Foo::Foo - MyApp::end + MyApp::Controller::Foo::end =item for a request for C MyApp::Controller::Foo::Bar::begin - MyApp::auto MyApp::Controller::Foo::auto MyApp::Controller::Foo::Bar::auto MyApp::Controller::Foo::Bar::default # for MyApp::Controller::Foo::Bar::foo @@ -957,28 +1135,33 @@ like this: false MyApp::Controller::Foo::Bar::begin - MyApp::auto + MyApp::Controller::Foo::auto # returns false, skips some calls: + # MyApp::Controller::Foo::Bar::auto - never called + # MyApp::Controller::Foo::Bar::foo - never called MyApp::Controller::Foo::Bar::end +You can also C in the auto action; in that case, the request will +go straight to the finalize stage, without processing further +actions. So in the above example, C +is skipped as well. + =back -An example of why one might use this is an authentication action: you -could set up a C action to handle authentication in your +An example of why one might use C is an authentication action: +you could set up a C action to handle authentication in your application class (which will always be called first), and if -authentication fails, returning 0 would skip any remaining methods -for that URL. +authentication fails, returning 0 would skip any remaining methods for +that URL. B Looking at it another way, C actions have to return a -true value to continue processing! You can also C in the auto -action; in that case, the request will go straight to the finalize -stage, without processing further actions. +true value to continue processing! =head4 URL Path Handling -You can pass variable arguments as part of the URL path, separated with -forward slashes (/). If the action is a Regex or LocalRegex, the '$' anchor -must be used. For example, suppose you want to handle C, -where C<$bar> and C<$baz> may vary: +You can pass arguments as part of the URL path, separated with forward +slashes (/). If the action is a Regex or LocalRegex, the '$' anchor +must be used. For example, suppose you want to handle +C, where C<$bar> and C<$baz> may vary: sub foo : Regex('^foo$') { my ($self, $context, $bar, $baz) = @_; } @@ -987,7 +1170,7 @@ But what if you also defined actions for C and C? sub boo : Path('foo/boo') { .. } sub hoo : Path('foo/boo/hoo') { .. } -Catalyst matches actions in most specific to least specific order: +Catalyst matches actions in most specific to least specific order - that is, whatever matches the most pieces of the path wins: /foo/boo/hoo /foo/boo @@ -996,11 +1179,28 @@ Catalyst matches actions in most specific to least specific order: 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 -available via C<@_>. +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 +same specificity (that is, they match the same quantity of the path), +there's no guarantee which will actually get called. Non-regex +matchers get tried first, followed by regex ones, but if you have, for +instance: + + package MyApp::Controller::Root; + + sub match1 :Path('/a/b') { } + + package MyApp::Controller::A; -=head4 Parameter Processing + sub b :Local { } # Matches /a/b + +then Catalyst will call the one it finds first. In summary, Don't Do +This. + +=head4 Query Parameter Processing Parameters passed in the URL query string are handled with methods in the L class. The C method is functionally @@ -1012,7 +1212,7 @@ modules that require this. 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); @@ -1065,9 +1265,9 @@ be reset. # 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... } @@ -1079,11 +1279,11 @@ you will have to refer to the method by absolute path. $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 { @@ -1091,7 +1291,7 @@ Here are some examples of how to forward to classes and methods. $c->forward('MyApp::Model::Hello'); # no method: will try 'process' } - package MyApp::Model::Hello; + package MyApp::View::Hello; sub say_hello { my ( $self, $c ) = @_; @@ -1103,6 +1303,28 @@ Here are some examples of how to forward to classes and methods. $c->res->body('Goodbye World!'); } +This mechanism is used by L to forward +to the C 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 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 instead, which will execute @@ -1110,7 +1332,6 @@ the Ced action and not return to the calling sub. In both cases, 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 @@ -1158,20 +1379,24 @@ IRC: Mailing lists: - http://lists.rawmode.org/mailman/listinfo/catalyst - http://lists.rawmode.org/mailman/listinfo/catalyst-dev + http://lists.scsys.co.uk/mailman/listinfo/catalyst + http://lists.scsys.co.uk/mailman/listinfo/catalyst-dev + +Wiki: -=head1 AUTHOR + http://dev.catalystframework.org/wiki -Sebastian Riedel, C -David Naughton, C -Marcus Ramberg, C -Jesse Sheidlower, C -Danijel Milicevic, C -Kieren Diment, C -Yuval Kogman, C +FAQ: + + http://dev.catalystframework.org/wiki/faq + +=head1 AUTHORS + +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