X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FCookbook.pod;h=1800657599c22cfa384df09b0a38e3e7dd7b5849;hp=104ab7426d44145b609b7ae005abb904dfa086ac;hb=e8200f38d465b85ad84eb11718db1e61230ce73b;hpb=a7b39a0c23a77dc84a30ca259156ca31f8921857 diff --git a/lib/Catalyst/Manual/Cookbook.pod b/lib/Catalyst/Manual/Cookbook.pod index 104ab74..1800657 100644 --- a/lib/Catalyst/Manual/Cookbook.pod +++ b/lib/Catalyst/Manual/Cookbook.pod @@ -1,3 +1,5 @@ +=encoding utf8 + =head1 NAME Catalyst::Manual::Cookbook - Cooking with Catalyst @@ -33,9 +35,12 @@ to go into this C method; see L). if ( scalar @{ $c->error } ) { $c->stash->{errors} = $c->error; + for my $error ( @{ $c->error } ) { + $c->log->error($error); + } $c->stash->{template} = 'errors.tt'; $c->forward('MyApp::View::TT'); - $c->error(0); + $c->clear_errors; } return 1 if $c->response->status =~ /^3\d\d$/; @@ -65,7 +70,7 @@ Normally you enable the debugging info by adding the C<-Debug> flag to your C statement . However, you can also enable it using environment variable, so you can (for example) get debug info without modifying your application scripts. Just set C or -CMYAPPE_DEBUG> to a true value. +C<< _DEBUG >> to a true value. =head2 Sessions @@ -107,61 +112,59 @@ retrieve the user data for you. =head3 Using a session Once the session modules are loaded, the session is available as C<< -$c->session >>, and can be writen to and read from as a simple hash +$c->session >>, and can be written to and read from as a simple hash reference. =head3 EXAMPLE - package MyApp; - use Moose; - use namespace::autoclean; - - use Catalyst qw/ - Session - Session::Store::FastMmap - Session::State::Cookie - /; - extends 'Catalyst'; - __PACKAGE__->setup; - - package MyApp::Controller::Foo; - use Moose; - use namespace::autoclean; - BEGIN { extends 'Catalyst::Controller' }; - ## Write data into the session - - sub add_item : Local { - my ( $self, $c ) = @_; - - my $item_id = $c->req->param("item"); - - push @{ $c->session->{items} }, $item_id; + package MyApp; + use Moose; + use namespace::autoclean; + + use Catalyst qw/ + Session + Session::Store::FastMmap + Session::State::Cookie + /; + extends 'Catalyst'; + __PACKAGE__->setup; + + package MyApp::Controller::Foo; + use Moose; + use namespace::autoclean; + BEGIN { extends 'Catalyst::Controller' }; + ## Write data into the session + + sub add_item : Local { + my ( $self, $c ) = @_; - } + my $item_id = $c->req->params->{item}; - ## A page later we retrieve the data from the session: + push @{ $c->session->{items} }, $item_id; + } - sub get_items : Local { - my ( $self, $c ) = @_; + ## A page later we retrieve the data from the session: - $c->stash->{items_to_display} = $c->session->{items}; + sub get_items : Local { + my ( $self, $c ) = @_; - } + $c->stash->{items_to_display} = $c->session->{items}; + } =head3 More information -L +L -L +L -L +L -L +L -L +L -L +L =head2 Configure your application @@ -171,11 +174,11 @@ separate configuration file. =head3 Using Config::General -L is a method for creating flexible +L is a method for creating flexible and readable configuration files. It's a great way to keep your Catalyst application configuration in one easy-to-understand location. -Now create C in your application home: +Now create F in your application home: name MyApp @@ -196,24 +199,32 @@ This is equivalent to: # configure base package __PACKAGE__->config( name => MyApp ); # configure authentication - __PACKAGE__->config->{authentication} = { - user_class => 'MyApp::Model::MyDB::Customer', - ... - }; + __PACKAGE__->config( + 'Plugin::Authentication' => { + user_class => 'MyApp::Model::MyDB::Customer', + ... + }, + _; # configure sessions - __PACKAGE__->config->{session} = { - expires => 3600, - ... - }; + __PACKAGE__->config( + session => { + expires => 3600, + ... + }, + ); # configure email sending - __PACKAGE__->config->{email} = [qw/SMTP localhost/]; + __PACKAGE__->config( email => [qw/SMTP localhost/] ); + +L explains precedence of multiple sources for configuration +values, how to access the values in your components, and many 'base' +config variables used internally. -See also L. +See also L. =head1 Skipping your VCS's directories -Catalyst uses Module::Pluggable to load Models, Views, and Controllers. -Module::Pluggable will scan through all directories and load modules +Catalyst uses L to load Models, Views, and Controllers. +L will scan through all directories and load modules it finds. Sometimes you might want to skip some of these directories, for example when your version control system makes a subdirectory with meta-information in every version-controlled directory. While @@ -229,7 +240,7 @@ You can make Catalyst skip these directories using the Catalyst config: setup_components => { except => qr/SCCS/ }, ); -See the Module::Pluggable manual page for more information on B +See the L manual page for more information on B and other options. =head1 Users and Access Control @@ -243,7 +254,7 @@ this. This is extensively covered in other documentation; see in particular L and the Authentication chapter -of the Tutorial at L. +of the Tutorial at L. =head2 Pass-through login (and other actions) @@ -297,9 +308,9 @@ C<< $c->user >> call. Examples: - Password - Simple username/password checking. - HTTPD - Checks using basic HTTP auth. - TypeKey - Check using the typekey system. + Password - Simple username/password checking. + HTTPD - Checks using basic HTTP auth. + TypeKey - Check using the typekey system. =head3 Storage backends @@ -309,8 +320,8 @@ within this system; you will need to do it yourself. Examples: - DBIC - Storage using a database via DBIx::Class. - Minimal - Storage using a simple hash (for testing). + DBIC - Storage using a database via DBIx::Class. + Minimal - Storage using a simple hash (for testing). =head3 User objects @@ -319,7 +330,7 @@ credential verifier, and is filled with the retrieved user information. Examples: - Hash - A simple hash of keys and values. + Hash - A simple hash of keys and values. =head3 ACL authorization @@ -348,67 +359,67 @@ the user is a member. =head3 EXAMPLE - package MyApp; - use Moose; - use namespace::autoclean; - extends qw/Catalyst/; - use Catalyst qw/ - Authentication - Authorization::Roles - /; + package MyApp; + use Moose; + use namespace::autoclean; + extends qw/Catalyst/; + use Catalyst qw/ + Authentication + Authorization::Roles + /; - __PACKAGE__->config( - authentication => { - default_realm => 'test', - realms => { - test => { - credential => { - class => 'Password', - password_field => 'password', - password_type => 'self_check', - }, - store => { - class => 'Htpasswd', - file => 'htpasswd', - }, - }, - }, - }, - ); + __PACKAGE__->config( + authentication => { + default_realm => 'test', + realms => { + test => { + credential => { + class => 'Password', + password_field => 'password', + password_type => 'self_check', + }, + store => { + class => 'Htpasswd', + file => 'htpasswd', + }, + }, + }, + }, + ); + + package MyApp::Controller::Root; + use Moose; + use namespace::autoclean; + + BEGIN { extends 'Catalyst::Controller' } + + __PACKAGE__->config(namespace => ''); + + sub login : Local { + my ($self, $c) = @_; + + if ( my $user = $c->req->params->{user} + and my $password = $c->req->param->{password} ) + { + if ( $c->authenticate( username => $user, password => $password ) ) { + $c->res->body( "hello " . $c->user->name ); + } else { + # login incorrect + } + } + else { + # invalid form input + } + } + + sub restricted : Local { + my ( $self, $c ) = @_; - package MyApp::Controller::Root; - use Moose; - use namespace::autoclean; - - BEGIN { extends 'Catalyst::Controller' } - - __PACKAGE__->config(namespace => ''); - - sub login : Local { - my ($self, $c) = @_; - - if ( my $user = $c->req->param("user") - and my $password = $c->req->param("password") ) - { - if ( $c->authenticate( username => $user, password => $password ) ) { - $c->res->body( "hello " . $c->user->name ); - } else { - # login incorrect - } - } - else { - # invalid form input - } - } - - sub restricted : Local { - my ( $self, $c ) = @_; - - $c->detach("unauthorized") - unless $c->check_user_roles( "admin" ); - - # do something restricted here - } + $c->detach("unauthorized") + unless $c->check_user_roles( "admin" ); + + # do something restricted here + } =head3 Using authentication in a testing environment @@ -446,7 +457,7 @@ determines what this user is allowed to do. Under role based access control each user is allowed to perform any number of roles. For example, at a zoo no one but specially trained -personnel can enter the moose cage (Mynd you, møøse bites kan be +personnel can enter the moose cage (Mynd you, møøse bites kan be pretty nasti!). For example: package Zoo::Controller::MooseCage; @@ -454,7 +465,7 @@ pretty nasti!). For example: sub feed_moose : Local { my ( $self, $c ) = @_; - $c->model( "Moose" )->eat( $c->req->param("food") ); + $c->model( "Moose" )->eat( $c->req->params->{food} ); } With this action, anyone can just come into the moose cage and feed @@ -476,7 +487,7 @@ And now our action should look like this: my ( $self, $c ) = @_; if ( $c->check_roles( "moose_feeder" ) ) { - $c->model( "Moose" )->eat( $c->req->param("food") ); + $c->model( "Moose" )->eat( $c->req->params->{food} ); } else { $c->stash->{error} = "unauthorized"; } @@ -562,14 +573,14 @@ clean up in your C private action instead. Also, it's important to note that if you restrict access to "/" then C, C, etc. will also be restricted. - MyApp->acl_allow_root_internals; + MyApp->acl_allow_root_internals; will create rules that permit access to C, C, and C in the root of your app (but not in any other controller). =head1 Models -Models are where application data belongs. Catalyst is exteremely +Models are where application data belongs. Catalyst is extremely flexible with the kind of models that it can use. The recipes here are just the start. @@ -586,7 +597,7 @@ write a simple component in Catalyst that slurps in an outside Model: __PACKAGE__->config( schema_class => 'Some::DBIC::Schema', - connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}]; + connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}], ); 1; @@ -674,25 +685,37 @@ Response: Now follow these few steps to implement the application: -1. Install Catalyst (5.61 or later), Catalyst::Plugin::XMLRPC (0.06 or -later) and SOAP::Lite (for XMLRPCsh.pl). +=over 4 + +=item 1. + +Install L (5.61 or later), L (0.06 or +later) and L (for F). -2. Create an application framework: +=item 2. + +Create an application framework: % catalyst.pl MyApp ... % cd MyApp -3. Add the XMLRPC plugin to MyApp.pm +=item 3. + +Add the XMLRPC plugin to MyApp.pm use Catalyst qw/-Debug Static::Simple XMLRPC/; -4. Add an API controller +=item 4. + +Add an API controller % ./script/myapp_create.pl controller API -5. Add a XMLRPC redispatch method and an add method with Remote -attribute to lib/MyApp/Controller/API.pm +=item 5. + +Add a XMLRPC redispatch method and an add method with Remote +attribute to F sub default :Path { my ( $self, $c ) = @_; @@ -711,8 +734,10 @@ class. The C method is not a traditional action; it has no private or public path. Only the XMLRPC dispatcher knows it exists. -6. That's it! You have built your first web service. Let's test it with -XMLRPCsh.pl (part of SOAP::Lite): +=item 6. + +That's it! You have built your first web service. Let's test it with +F (part of L): % ./script/myapp_server.pl ... @@ -737,7 +762,7 @@ enforce a specific one. Views pertain to the display of your application. As with models, Catalyst is uncommonly flexible. The recipes below are just a start. -=head2 Catalyst::View::TT +=head2 L One of the first things you probably want to do when starting a new Catalyst application is set up your View. Catalyst doesn't care how you @@ -745,17 +770,17 @@ display your data; you can choose to generate HTML, PDF files, or plain text if you wanted. Most Catalyst applications use a template system to generate their HTML, -and though there are several template systems available, Template -Toolkit is probably the most popular. +and though there are several template systems available, +L