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=a15f7d12c23e5d3d2e4ea623011f98818fcb5a40;hp=61eeddf42d5f9b234668b62c009ca0b51f36b0b0;hb=fce83e5f2a2da9f9117562d05aec1e161cc3c109;hpb=0c51850e9e3daa7ba2dc9194dec7b8fc2b3a64c0 diff --git a/lib/Catalyst/Manual/Intro.pod b/lib/Catalyst/Manual/Intro.pod index 61eeddf..a15f7d1 100644 --- a/lib/Catalyst/Manual/Intro.pod +++ b/lib/Catalyst/Manual/Intro.pod @@ -97,18 +97,18 @@ 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< :Local > attribute are equivalent to -using a C<:Path('/action_name') > attribute (note the leading slash). -So our action could be equivalently: +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 hello : Path('/hello') { + sub hi : Path('hello') { my ( $self, $context ) = @_; $context->response->body('Hello World!'); } @@ -116,8 +116,11 @@ So our action could be equivalently: =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 @@ -526,27 +529,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: @@ -564,6 +594,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 @@ -574,9 +607,7 @@ configure your application, load plugins, and extend Catalyst. use strict; use parent qw/Catalyst/; - __PACKAGE__->setup(qw/-Debug ConfigLoader Static::Simple/); - # note you can still use use Catalyst qw/@plugins/ instead of the - # above two lines + use Catalyst qw/-Debug ConfigLoader Static::Simple/; MyApp->config( name => 'My Application', @@ -654,7 +685,7 @@ information. $c->res->status(404); $c->res->redirect('http://oook.de'); -=item * L +=item * config $c->config $c->config->{root}; @@ -699,21 +730,83 @@ 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'; @@ -727,107 +820,159 @@ this: } 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 * Namespace-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> is equivalent C<:Local> one level higher in +the namespace. + + 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. + + +=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. + +Actions with the C<:Local> attribute are similarly equivalent to +C<:Path('action_name')>: -=item * B + 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: - - package MyApp::Controller::Root - sub foo : Local { } - -=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. +This differs from the previous example in that it will match +http://localhost:3000/my/controller/foo/widget23 - and a number of +other paths. -Note that actions with the C< :Local > attribute are equivalent to the -<:Path('action_name') > so sub foo : Local { } is equivalent to - - - sub foo : Path('foo') { } +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 +=item * Chained handlers (C<:Chained>) Catalyst also provides a method to build and dispatch chains of actions, like @@ -842,67 +987,66 @@ 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. Catalyst's :Private attribute is -exclusive and doesn't work with other attributes (so will not work -combined with Path or Chained attributes). With the exception of the -C< index >, C< auto > and C< default > actions, Private actions can -only be executed from inside a Catalyst application, by calling the -C or C methods: +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. + +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). + +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: $c->forward('foo'); # or $c->detach('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 +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')>. -=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, - - sub bar :Local - -would match any URL starting /foo/bar/. To restrict this you can do - - sub bar :Local :Args(1) - -to only match /foo/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 -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. B: in older Catalyst applications you -will see C which is roughly speaking equivalent. +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. =item * B @@ -918,44 +1062,48 @@ 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 : Path { } - 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 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: @@ -964,15 +1112,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 @@ -992,28 +1138,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) = @_; } @@ -1022,7 +1173,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 @@ -1032,10 +1183,27 @@ 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<@_>. +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') { } -=head4 Parameter Processing + package MyApp::Controller::A; + + 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 @@ -1196,6 +1364,14 @@ Mailing lists: http://lists.scsys.co.uk/mailman/listinfo/catalyst http://lists.scsys.co.uk/mailman/listinfo/catalyst-dev +Wiki: + + http://dev.catalystframework.org/wiki + +FAQ: + + http://dev.catalystframework.org/wiki/faq + =head1 AUTHOR Sebastian Riedel, C