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=7aa494deed5940b6b8c8d2912f2f900b3d27d6c9;hp=3538185d77c454b7d4e1ac568ea51e7f88e22403;hb=388f66e0214312ffa77b48128d2fa2e1932b4669;hpb=11876a3b2caff61a98ea1830ab40c966082e4bd8 diff --git a/lib/Catalyst/Manual/Intro.pod b/lib/Catalyst/Manual/Intro.pod index 3538185..7aa494d 100644 --- a/lib/Catalyst/Manual/Intro.pod +++ b/lib/Catalyst/Manual/Intro.pod @@ -15,15 +15,15 @@ with Catalyst, see L. 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 +L, upon which it was originally based. Its most +important design philosophy 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 +example, this leads to Catalyst being better suited to system integration tasks than other web frameworks. =head3 MVC @@ -53,7 +53,7 @@ L, L... =item * B Control the whole request phase, check parameters, dispatch actions, flow -control. Catalyst itself! +control. This is the meat of where Catalyst works. =back @@ -104,7 +104,7 @@ example: Now http://localhost:3000/hello prints "Hello World!". -Note that actions with the C< :Global > attribute are equivalent to +Note that actions with the C< :Local > attribute are equivalent to using a C<:Path('action_name') > attribute, so our action could be equivalently: @@ -122,6 +122,12 @@ 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). +=item * PSGI Support + +Starting with Catalyst version 5.9 Catalyst ships with L integration +for even more powerful and flexible testing and deployment options. See +L for details. + =back =head3 Simplicity @@ -171,17 +177,11 @@ running, using the helper scripts described above. =head3 Install -Installation of Catalyst can be a time-consuming effort, due to its -large number of dependencies. Although most of the frustrations -associated with this are now ironed out and a simple C or C are now usually -straightforward, if you still have problems, you can use 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' + # perl -MCPAN -e 'install Catalyst::View::TT' =head3 Setup @@ -196,7 +196,7 @@ 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 +L for more details. @@ -230,7 +230,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. @@ -238,7 +238,7 @@ 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. @@ -248,9 +248,10 @@ 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::Controller'; + BEGIN { extends 'Catalyst::Controller' } __PACKAGE__->config( foo => 'bar' ); @@ -264,25 +265,14 @@ short alias for each one. =over 4 -=item * B - -=item * B +=item * B =item * B -=item * B - =item * B -=item * B - =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 @@ -304,9 +294,9 @@ where the first C tells the script that the name of the view should be C, and the second that it should be a Template Toolkit view.) This gives us a process() method and we can now just do -$c->forward('MyApp::View::TT') to render our templates. The base class +C<< $c->forward('MyApp::View::TT') >> to render our templates. The base class makes process() implicit, so we don't have to say -C<$c-Eforward(qw/MyApp::View::TT process/)>. +C<< $c->forward(qw/MyApp::View::TT process/) >>. sub hello : Global { my ( $self, $c ) = @_; @@ -325,7 +315,7 @@ 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 end up looking at the debug +C<< $c->config->{root} >>, or you'll end up looking at the debug screen. =head4 Models @@ -363,7 +353,7 @@ 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 can automaticall load table layouts and +L can automatically load table layouts and relationships, and convert them into a static schema definition C, which you can edit later. @@ -373,15 +363,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') ); } @@ -396,14 +386,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; } @@ -412,7 +402,7 @@ gain several things: you don't have to C each component, Catalyst will find and load it automatically at compile-time; you can C to the module, which can only be done to Catalyst components. Only Catalyst components can be fetched with -C<$c-Emodel('SomeModel')>. +C<< $c->model('SomeModel') >>. Happily, since many people have existing Model classes that they would like to use with Catalyst (or, conversely, they want to @@ -469,7 +459,7 @@ Using plugins from a Model (for example L). From a style perspective it's usually considered bad form 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 +find that it does not make sense at all to use an auxiliary controller around the model, and the model's need to access C<$c> cannot be sidestepped, there exists a power tool called L. @@ -482,9 +472,9 @@ application. use base qw/Catalyst::Controller/; - sub login : Path("login") { } + sub sign_in : Path("sign-in") { } sub new_password : Path("new-password") { } - sub logout : Path("logout") { } + sub sign_out : Path("sign-out") { } package MyApp::Controller::Catalog; @@ -524,7 +514,7 @@ equivalent to the same controller above: =head3 ACCEPT_CONTEXT -Whenever you call $c->component("Foo") you get back an object - the +Whenever you call C<< $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. @@ -540,7 +530,7 @@ 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 +scope where it is needed 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: @@ -572,7 +562,7 @@ In a subroutine in the model code, we can then do this: 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 +to grab the C<< $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 @@ -633,7 +623,7 @@ Optionally, you can specify a B parameter for templates and static data. If omitted, Catalyst will try to auto-detect the directory's location. You can define as many parameters as you want for plugins or whatever you need. You can access them anywhere in your application via -C<$context-Econfig-E{$param_name}>. +C<< $context->config->{$param_name} >>. =head3 Context @@ -765,10 +755,10 @@ 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 +The URL (for example C) 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 +(C in this example) and the path, which the +server uses to decide what to return (C). 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. @@ -790,7 +780,7 @@ of Catalyst component class names. =item * B -Note that __PACKAGE__->config->{namespace} can be used to override the +Note that C<< __PACKAGE__->config->(namespace => ... ) >> can be used to override the current namespace when matching. So: package MyApp::Controller::Example; @@ -798,37 +788,41 @@ current namespace when matching. So: would normally use 'example' as its namespace for matching, but if this is specially overridden with - __PACKAGE__->config->{namespace}='thing'; + __PACKAGE__->config( namespace => 'thing' ); it matches using the namespace 'thing' instead. -=item * B +=item * B 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/ ): +application (e.g. C): package MyApp::Controller::Root; use base 'Catalyst::Controller'; + # Sets the actions in this controller to be registered with no prefix # so they function identically to actions created in MyApp.pm - __PACKAGE__->config->{namespace} = ''; + + __PACKAGE__->config( namespace => ''); + sub default : Path { my ( $self, $context ) = @_; $context->response->status(404); $context->response->body('404 not found'); } + 1; The code - __PACKAGE__->config->{namespace} = ''; + __PACKAGE__->config( namespace => '' ); makes the controller act as if its namespace is empty. As you'll see -below, an empty namespace makes many of the URL-matching attributes, -such as :Path, :Local and :Global matches, match at the start of the -URL path. +below, an empty namespace makes many of the URL-matching attributes, such +as :Path and :Local match at the start of the URL path (i.e. the +application root). =back @@ -847,32 +841,43 @@ of the path is passed as arguments. =item * Namespace-prefixed (C<:Local>) - package MyApp::Controller::My::Controller; + package MyApp::Controller::My::Controller; sub foo : Local { } -Matches any URL beginning with> http://localhost:3000/my/controller/foo. The namespace and +Matches any URL beginning with> C. The namespace and subroutine name together determine the path. -=item * Namespace-level (C<:Global>) +=item * Root-level (C<:Global>) package MyApp::Controller::Foo; - sub foo : Global { } -Matches http://localhost:3000/foo - that is, the action is mapped -directly to the controller namespace, ignoring the function name. + sub bar : Global { + my ($self, $c) = @_; + $c->res->body( + $c->res->body('sub bar in Controller::Foo triggered on a request for ' + . $c->req->uri)); + } -C<:Global> is equivalent C<:Local> one level higher in -the namespace. +1; - package MyApp::Controller::Root; - __PACKAGE__->config->{namespace}=''; - sub foo : Local { } +Matches C - that is, the action is mapped +directly to the method name, ignoring the controller namespace. + +C<:Global> always matches from the application root: it is simply +shorthand for C<:Path('/methodname')>. C<:Local> is shorthand for +C<:Path('methodname')>, which takes the controller namespace as described +above. -Use whichever makes the most sense for your application. +Usage of the C handler is rare in all but very old Catalyst +applications (e.g. before Catalyst 5.7). The use cases where C +used to make sense are now largely replaced by the C dispatch +type, or by empty C declarations on an controller action. C +is still included in Catalyst for backwards compatibility, although +legitimate use-cases for it may still exist. -=item * Changing handler behaviour: adding arguments (C<:Args>) +=item * Changing handler behaviour: eating arguments (C<:Args>) -Args is not an action type per se, but an action modifier - it adds a +C<: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, @@ -886,6 +891,18 @@ would match any URL starting /foo/bar. To restrict this you can do to only match URLs starting /foo/bar/* - with one additional path element required after 'bar'. +NOTE that adding C<:Args(0)> and omitting C<:Args> are B +the same thing. + +C<:Args(0)> means that no arguments are taken. Thus, the URL and path must +match precisely. + +No C<: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, @@ -893,7 +910,7 @@ 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 : +starting with C: package MyApp::Controller::My::Controller; sub bar : Path('foo/bar') { } @@ -904,7 +921,7 @@ match from the start of the URL path. Example: package MyApp::Controller::My::Controller; sub bar : Path('/foo/bar') { } -This matches URLs beginning http://localhost:3000/foo/bar. +This matches URLs beginning with C. Empty C definitions match on the namespace only, exactly like C<:Global>. @@ -912,29 +929,33 @@ C<:Global>. package MyApp::Controller::My::Controller; sub bar : Path { } -The above code matches http://localhost:3000/my/controller. +The above code matches C. Actions with the C<:Local> attribute are similarly equivalent to C<:Path('action_name')>: - sub foo : Local { } + sub foo : Local { } -is equivalent to +is equivalent to sub foo : Path('foo') { } -=item * Pattern-match (C<:Regex> and C<:LocalRegex>) - +=item * Pattern match (C<:Regex> and C<:LocalRegex>) + +B Use Chained methods or other techniques. +If you really depend on this, install the standalone +L distribution. + package MyApp::Controller::My::Controller; sub bar : Regex('^item(\d+)/order(\d+)$') { } This matches any URL that matches the pattern in the action key, e.g. -http://localhost:3000/item23/order42. The '' around the regexp is +C. The '' around the regexp is optional, but perltidy likes it. :) 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 - use a C<:LocalRegex> action instead. package MyApp::Controller::My::Controller; @@ -942,7 +963,7 @@ C<:LocalRegex> action instead. 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. +C. If you omit the "C<^>" from either sort of regex, then it will match any depth from the base path: @@ -951,14 +972,14 @@ from the base path: sub bar : LocalRegex('widget(\d+)$') { } This differs from the previous example in that it will match -http://localhost:3000/my/controller/foo/widget23 - and a number of +C - and a number of other paths. 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 +are available in the C<< $c->req->captures >> 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 +C<< $c->req->captures->[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. @@ -1009,7 +1030,7 @@ 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')>. +C<< $c->forward('/catalog/order/process/bar') >>. =back @@ -1092,7 +1113,7 @@ turn. sub auto : Private { } C, however, doesn't override like this: providing they exist, -C, C and +C, C and C would be called in turn. Here are some examples of the order in which the various built-ins @@ -1147,7 +1168,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! +true value to continue processing! =head4 URL Path Handling @@ -1172,8 +1193,8 @@ Catalyst matches actions in most specific to least specific order - that is, wha So Catalyst would never mistakenly dispatch the first two URLs to the '^foo$' action. -If a Regex or LocalRegex action doesn't use the '$' anchor, the action will -still match a URL containing arguments; however the arguments won't be +If a Regex or LocalRegex action doesn't use the '$' anchor, the action will +still match a URL containing arguments; however the arguments won't be available via C<@_>, because the Regex will 'eat' them. Beware! If you write two matchers, that match the same path, with the @@ -1197,7 +1218,7 @@ This. Parameters passed in the URL query string are handled with methods in the L class. The C method is functionally -equivalent to the C method of C and can be used in +equivalent to the C method of L and can be used in modules that require this. # http://localhost:3000/catalog/view/?category=hardware&page=3 @@ -1205,7 +1226,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); @@ -1242,13 +1263,13 @@ debugging enabled). } A C does not create a new request, so your request object -(C<$c-Ereq>) will remain unchanged. This is a key difference between +(C<< $c->req >>) 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> +in an anonymous array. In this case C<< $c->req->args >> will be changed for the duration of the C only; upon -return, the original value of C<$c-Ereq-Eargs> will +return, the original value of C<< $c->req->args >> will be reset. sub hello : Global { @@ -1258,9 +1279,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... } @@ -1272,11 +1293,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 { @@ -1284,7 +1305,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 ) = @_; @@ -1296,6 +1317,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 @@ -1303,7 +1346,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 @@ -1326,7 +1368,7 @@ that can be extended as you develop your project. To write your own comprehensive test scripts, L is an invaluable tool. -For more testing ideas, see L. +For more testing ideas, see L. Have fun! @@ -1362,17 +1404,13 @@ FAQ: http://dev.catalystframework.org/wiki/faq -=head1 AUTHOR +=head1 AUTHORS -Sebastian Riedel, C -David Naughton, C -Marcus Ramberg, C -Jesse Sheidlower, C -Danijel Milicevic, C -Kieren Diment, C -Yuval Kogman, C +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