X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FIntro.pod;h=39cf95e20008cd0e51cd7800ae08446edad78db7;hb=7f71afbe8ecd0796cd37dd690bba0510c879f261;hp=65c633dd74fcf16d35c8b0237ccf7c7457713c1b;hpb=fabf3a100d2255ee3d0d4f7af57b57cd658feceb;p=catagits%2FCatalyst-Runtime.git diff --git a/lib/Catalyst/Manual/Intro.pod b/lib/Catalyst/Manual/Intro.pod index 65c633d..39cf95e 100644 --- a/lib/Catalyst/Manual/Intro.pod +++ b/lib/Catalyst/Manual/Intro.pod @@ -8,12 +8,22 @@ This is a brief introduction to Catalyst. It explains the most important 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. +For a systematic step-by-step introduction to writing an application +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. +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. 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 @@ -24,15 +34,15 @@ modify code that handles one concern without affecting code that handles the others. Catalyst promotes the re-use of existing Perl modules that already handle common web application concerns well. -Here's how the M, V, and C map to those concerns, with examples of -well-known Perl modules you may want to use for each. +Here's how the Model, View, and Controller map to those concerns, with +examples of well-known Perl modules you may want to use for each. =over 4 =item * B Access and modify content (data). L, L, -L, L... +L, L... =item * B @@ -46,17 +56,16 @@ control. Catalyst itself! =back -If you're unfamiliar with MVC and design patterns, you may want to check -out the original book on the subject, I, by Gamma, -Helm, Johnson, and Vlissides, also known as the Gang of Four (GoF). -Many, many web application frameworks are based on MVC, including all -those listed above. +If you're unfamiliar with MVC and design patterns, you may want to +check out the original book on the subject, I, by +Gamma, Helm, Johnson, and Vlissides, also known as the Gang of Four +(GoF). Many, many web application frameworks are based on MVC, which +is becoming a popular design method for web applications. =head3 Flexibility -Catalyst is much more flexible than many other frameworks. We'll talk -more about this later, but rest assured you can use your favorite Perl -modules with Catalyst. +Catalyst is much more flexible than many other frameworks. Rest assured +you can use your favorite Perl modules with Catalyst. =over 4 @@ -80,7 +89,7 @@ multiple Catalyst applications. =item * B -Catalyst allows you to dispatch any URLs to any application L, +Catalyst allows you to dispatch any URLs to any application L, even through regular expressions! Unlike most other frameworks, it doesn't require mod_rewrite or class and method names in URLs. @@ -94,9 +103,10 @@ example: Now http://localhost:3000/hello prints "Hello World!". -=item * B +=item * B -Use L or L. +Use L or L. Other +engines are also available. =back @@ -110,7 +120,7 @@ simple way. =item * B Components interoperate very smoothly. For example, Catalyst -automatically makes a L object available to every +automatically makes a L object available to every component. Via the context, you can access the request object, share data between components, and control the flow of your application. Building a Catalyst application feels a lot like snapping @@ -134,7 +144,8 @@ framework, making it easy to test applications from the command line. =item * B Catalyst provides helper scripts to quickly generate running starter -code for components and unit tests. See L. +code for components and unit tests. Install L and see +L. =back @@ -145,7 +156,14 @@ running, using the helper scripts described above. =head3 Install - $ perl -MCPAN -e 'install Task::Catalyst' +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. + + # perl cat-install + # perl -MCPAN -e 'install Catalyst::Devel' =head3 Setup @@ -161,6 +179,10 @@ running, using the helper scripts described above. Now visit these locations with your favorite browser or user agent to see Catalyst in action: +(NOTE: Although we create a controller here, we don't actually use it. +Both of these URLs should take you to the welcome page.) + + =over 4 =item http://localhost:3000/ @@ -180,13 +202,13 @@ and other parts of a Catalyst application. In addition to the Model, View, and Controller components, there's a single class that represents your application itself. This is where you -configure your application, load plugins, define application-wide -actions, and extend Catalyst. +configure your application, load plugins, and extend Catalyst. package MyApp; use strict; - use Catalyst qw/-Debug/; + use Catalyst qw/-Debug/; # Add other plugins here, e.g. + # for session support MyApp->config( name => 'My Application', @@ -194,16 +216,12 @@ actions, and extend Catalyst. # You can put anything else you want in here: my_configuration_variable => 'something', ); - - sub default : Private { - my ( $self, $context ) = @_; - $context->response->body('Catalyst rocks!'); - } - 1; -For most applications, Catalyst requires you to define only one config -parameter: +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 L, +below), to avoid namespace collisions. =over 4 @@ -223,7 +241,7 @@ C<$context-Econfig-E{$param_name}>. Catalyst automatically blesses a Context object into your application class and makes it available everywhere in your application. Use the -Context to directly interact with Catalyst and glue your L +Context to directly interact with Catalyst and glue your L together. For example, if you need to use the Context from within a Template Toolkit template, it's already there: @@ -255,6 +273,7 @@ query parameters, cookies, uploads, headers, and more. $c->req->cookies->{sessionid}; $c->req->headers->content_type; $c->req->base; + $c->req->uri_with( { page = $pager->next_page } ); =item * L @@ -284,6 +303,10 @@ information. $c->stash $c->stash->{foo} = 'bar'; + $c->stash->{baz} = {baz => 'qox'}; + $c->stash->{fred} = [qw/wilma pebbles/]; + +and so on. =back @@ -303,7 +326,9 @@ application components. For an example, we return to our 'hello' action: Note that the stash should be used only for passing data in an individual request cycle; it gets cleared at a new request. If you need -to maintain more persistent data, use a session. +to maintain persistent data, use a session. See +L for a comprehensive set of +Catalyst-friendly session-handling tools. =head3 Actions @@ -315,6 +340,29 @@ http://localhost.3000/foo/bar) consists of two parts, the base note that the trailing slash after the hostname[:port] always belongs to base and not to the action. +=over 4 + +=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: + + 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 { + my ( $self, $context ) = @_; + $context->response->body('Catalyst rocks!'); + } + 1; + +=back + +=head4 Action types + Catalyst supports several types of actions: =over 4 @@ -373,19 +421,23 @@ http://localhost:3000/catalog/foo/widget23 as well. 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-Esnippets> array. In the above example, "widget23" +the C<$c-Ereq-Ecaptures> array. In the above example, "widget23" would capture "23" in the above example, and -C<$c-Ereq-Esnippets-E[0]> would be "23". If you want to pass +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; + package MyApp::Controller::Foo; sub foo : Global { } -Matches http://localhost:3000/foo. The function name is mapped directly -to the application base. +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) @@ -402,6 +454,24 @@ Catalyst ("MyApp::Controller" in the above example), replaces "::" with explanation of the pre-defined meaning of Catalyst component class names. +=item * B + +Catalyst also provides a method to build and dispatch chains of actions, +like + + sub catalog : Chained : CaptureArgs(1) { + my ( $self, $c, $arg ) = @_; + ... + } + + sub item : Chained('catalog') : Args(1) { + my ( $self, $c, $arg ) = @_; + ... + } + +to handle a C path. For extensive information about this +dispatch type, please see L. + =item * B sub foo : Private { } @@ -419,6 +489,21 @@ 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 @@ -440,10 +525,12 @@ displaying a generic frontpage for the main app, or an error page for individual controllers. 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. +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 @@ -479,6 +566,8 @@ run in place of C if you're in the C namespace, and C would override this in turn. +=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 @@ -534,7 +623,7 @@ 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 autochain +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. @@ -613,10 +702,9 @@ debugging enabled). $c->res->body( $c->stash->{message} ); } -A C does not create a new request, so your request -object (C<$c-Ereq>) will remain unchanged. This is a -key difference between using C and issuing a -redirect. +A C does not create a new request, so your request object +(C<$c-Ereq>) will remain unchanged. This is a key difference between +using C and issuing a redirect. You can pass new arguments to a C by adding them in an anonymous array. In this case C<$c-Ereq-Eargs> @@ -679,7 +767,7 @@ method. =head3 Components Catalyst has an uncommonly flexible component system. You can define as -many L, L, and L as you like. +many L, L, and L as you like. All components must inherit from L, which provides a simple class structure and some common class methods like C and @@ -698,7 +786,7 @@ You don't have to C or otherwise register Models, Views, and Controllers. Catalyst automatically discovers and instantiates them when you call C 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 @@ -716,6 +804,11 @@ can use some very terse aliases for each one. =back +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. + =head4 Views To show how to define views, we'll use an already-existing base class for the @@ -754,9 +847,12 @@ C<$c-Eforward(qw/MyApp::View::TT process/)>. You normally render templates at the end of a request, so it's a perfect use for the global C action. +In practice, however, you would use a default C action as supplied +by L. + Also, be sure to put the template under the directory specified in -C<$c-Econfig-E{root}>, or you'll be forced to look at our -eyecandy debug screen. ;) +C<$c-Econfig-E{root}>, or you'll end up looking at the debug +screen. =head4 Models @@ -820,9 +916,9 @@ can always call an outside module that serves as your Model: $c->stash->{template} = 'list.tt'; - use Some::Outside::DBIC::Module; - my @records = Some::Outside::DBIC::Module->search({ - artist => 'sri', + use Some::Outside::Database::Module; + my @records = Some::Outside::Database::Module->search({ + artist => 'Led Zeppelin', }); $c->stash->{records} = \@records; @@ -845,7 +941,7 @@ Catalyst that slurps in an outside Model: use base qw/Catalyst::Model::DBIC::Schema/; __PACKAGE__->config( schema_class => 'Some::DBIC::Schema', - connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}]; + connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}] ); 1; @@ -859,26 +955,153 @@ application. package MyApp::Controller::Login; - sub sign-in : Local { } - sub new-password : Local { } - sub sign-out : Local { } + use base qw/Catalyst::Controller/; + + sub sign_in : Path("sign-in") { } + sub new_password : Path("new-password") { } + sub sign_out : Path("sign-out") { } package MyApp::Controller::Catalog; + use base qw/Catalyst::Controller/; + sub view : Local { } sub list : Local { } package MyApp::Controller::Cart; + use base qw/Catalyst::Controller/; + sub add : Local { } sub update : Local { } sub order : Local { } +Note that you can also supply attributes via the Controller's config so long +as you have at least one attribute on a subref to be exported (:Action is +commonly used for this) - for example the following is equivalent to the same +controller above + + package MyApp::Controller::Login; + + use base qw/Catalyst::Controller/; + + __PACKAGE__->config( + actions => { + 'sign_in' => { Path => 'sign-in' }, + 'new_password' => { Path => 'new-password' }, + 'sign_out' => { Path => 'sign-out' }, + }, + ); + + sub sign_in : Action { } + sub new_password : Action { } + sub sign_out : Action { } + +=head3 Models + +Models are providers of data. This data could come from anywhere - a +search engine index, a database table, etc. Typically the data source +does not have much to do with web applications or Catalyst - it could be +used to write an offline report generator or a command line tool just +the same. + +The common approach to writing a Catalyst-style model for your +application is wrapping a generic model (e.g. L, a +bunch of XMLs, or anything really) with an object that contains +configuration data, convenience methods, and so forth. + +#### editor: move this part to =head3 Components somehow, right after this +#### section - this will require deeply rephrasing this paragraph. + +Technically, within Catalyst a model is a B - an instance of +the model's class belonging to the application. It is important to +stress that the lifetime of these objects is per application, not per +request. + +While the model base class (L) provides things like +C and stuff to better integrate the model into the application, +sometimes this is not enough, and the model requires access to C<$c> +itself. + +Situations where this need might arise include: + +=over 4 + +=item * + +Interacting with another model + +=item * + +Using per-request data to control behavior + +=item * + +Using plugins in (for example L). + +=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. + +#### 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 +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. + +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: + +Add a field to C<$c>, like C. Then write your +C method to look like this: + + sub ACCEPT_CONTEXT { + my ( $self, $c ) = @_; + + if ( my $per_request = $c->my_model_instance ) { + return $per_request; + } else { + my $new_instance = bless { %$self, c => $c }, ref($self); + Scalar::Util::weaken($new_instance->{c}); # or we have a circular reference + $c->my_model_instance( $new_instance ); + return $new_instance; + } + } + + =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... @@ -910,6 +1133,8 @@ David Naughton, C Marcus Ramberg, C Jesse Sheidlower, C Danijel Milicevic, C +Kieren Diment, C +Yuval Kogman, C =head1 COPYRIGHT