From: Kennedy Clark Date: Sun, 24 May 2009 22:06:59 +0000 (+0000) Subject: Merge from depluralization branch X-Git-Tag: v5.8005~144 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=commitdiff_plain;h=3b1fa91be1d89d2297aa9e8e83462344d9cd9820;hp=325bc0fd9f3c14fc336ddc74fdaa42e18aa3b4fe Merge from depluralization branch --- diff --git a/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod b/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod index cbcf259..1c7176d 100644 --- a/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod +++ b/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod @@ -132,7 +132,7 @@ following method: # is shorthand for "$form->submitted && !$form->has_errors" if ($form->submitted_and_valid) { # Create a new book - my $book = $c->model('DB::Books')->new_result({}); + my $book = $c->model('DB::Book')->new_result({}); # Save the form data for the book $form->model->update($book); # Set a status message for the user @@ -142,7 +142,7 @@ following method: $c->detach; } else { # Get the authors from the DB - my @author_objs = $c->model("DB::Authors")->all(); + my @author_objs = $c->model("DB::Author")->all(); # Create an array of arrayrefs where each arrayref is an author my @authors; foreach (sort {$a->last_name cmp $b->last_name} @author_objs) { @@ -270,17 +270,21 @@ running) and restart it: Login as C (password: mypass). Once at the Book List page, click the new HTML::FormFu "Create" link at the bottom to display the -form. Fill in the following values: Title = "Internetworking with -TCP/IP Vol. II", Rating = "4", and Author = "Comer". Click Submit, -and you will be returned to the Book List page with a "Book created" -status message displayed. +form. Fill in the following values: -Also note that this implementation allows you to can create books with + Title = "Internetworking with TCP/IP Vol. II" + Rating = "4" + Author = "Comer" + +Click the Submit button, and you will be returned to the Book List page +with a "Book created" status message displayed. + +Also note that this implementation allows you to create books with any bogus information. Although we have constrained the authors with the drop-down list (note that this isn't bulletproof because we still have not prevented a user from "hacking" the form to specify other values), there are no restrictions on items such as the length of the title (for -example, you can create a one-letter title) and value for the rating +example, you can create a one-letter title) and the value of the rating (you can use any number you want, and even non-numeric values with SQLite). The next section will address this concern. @@ -478,7 +482,7 @@ bottom: $c->detach; } else { # Get the authors from the DB - my @author_objs = $c->model("DB::Authors")->all(); + my @author_objs = $c->model("DB::Author")->all(); # Create an array of arrayrefs where each arrayref is an author my @authors; foreach (sort {$a->last_name cmp $b->last_name} @author_objs) { diff --git a/lib/Catalyst/Manual/Tutorial/Authentication.pod b/lib/Catalyst/Manual/Tutorial/Authentication.pod index 2d194c7..0d7e7ab 100644 --- a/lib/Catalyst/Manual/Tutorial/Authentication.pod +++ b/lib/Catalyst/Manual/Tutorial/Authentication.pod @@ -82,9 +82,9 @@ authorization section, Chapter 6). Create a new SQL script file by opening C in your editor and insert: -- - -- Add users and roles tables, along with a many-to-many join table + -- Add user and role tables, along with a many-to-many join table -- - CREATE TABLE users ( + CREATE TABLE user ( id INTEGER PRIMARY KEY, username TEXT, password TEXT, @@ -93,11 +93,11 @@ C in your editor and insert: last_name TEXT, active INTEGER ); - CREATE TABLE roles ( + CREATE TABLE role ( id INTEGER PRIMARY KEY, role TEXT ); - CREATE TABLE user_roles ( + CREATE TABLE user_role ( user_id INTEGER, role_id INTEGER, PRIMARY KEY (user_id, role_id) @@ -105,21 +105,20 @@ C in your editor and insert: -- -- Load up some initial test data -- - INSERT INTO users VALUES (1, 'test01', 'mypass', 't01@na.com', 'Joe', 'Blow', 1); - INSERT INTO users VALUES (2, 'test02', 'mypass', 't02@na.com', 'Jane', 'Doe', 1); - INSERT INTO users VALUES (3, 'test03', 'mypass', 't03@na.com', 'No', 'Go', 0); - INSERT INTO roles VALUES (1, 'user'); - INSERT INTO roles VALUES (2, 'admin'); - INSERT INTO user_roles VALUES (1, 1); - INSERT INTO user_roles VALUES (1, 2); - INSERT INTO user_roles VALUES (2, 1); - INSERT INTO user_roles VALUES (3, 1); + INSERT INTO user VALUES (1, 'test01', 'mypass', 't01@na.com', 'Joe', 'Blow', 1); + INSERT INTO user VALUES (2, 'test02', 'mypass', 't02@na.com', 'Jane', 'Doe', 1); + INSERT INTO user VALUES (3, 'test03', 'mypass', 't03@na.com', 'No', 'Go', 0); + INSERT INTO role VALUES (1, 'user'); + INSERT INTO role VALUES (2, 'admin'); + INSERT INTO user_role VALUES (1, 1); + INSERT INTO user_role VALUES (1, 2); + INSERT INTO user_role VALUES (2, 1); + INSERT INTO user_role VALUES (3, 1); Then load this into the C database with the following command: $ sqlite3 myapp.db < myapp02.sql - =head2 Add User and Role Information to DBIC Schema Although we could manually edit the DBIC schema information to include @@ -135,7 +134,7 @@ option on the DBIC model helper to do most of the work for us: exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm" $ $ ls lib/MyApp/Schema/Result - Authors.pm BookAuthors.pm Books.pm Roles.pm UserRoles.pm Users.pm + Author.pm BookAuthor.pm Book.pm Role.pm User.pm UserRole.pm Notice how the helper has added three new table-specific result source files to the C directory. And, more @@ -144,12 +143,12 @@ files, those changes would have only been written above the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-edited enhancements would have been preserved. -Speaking of "hand-edit ted enhancements," we should now add +Speaking of "hand-editted enhancements," we should now add relationship information to the three new result source files. Edit each of these files and add the following information between the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>: -C: +C: # # Set relationships: @@ -160,7 +159,7 @@ C: # 1) Name of relationship, DBIC will create accessor with this name # 2) Name of the model class referenced by this relationship # 3) Column name in *foreign* table (aka, foreign key in peer table) - __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::Result::UserRoles', 'user_id'); + __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::Result::UserRole', 'user_id'); # many_to_many(): # args: @@ -171,7 +170,7 @@ C: __PACKAGE__->many_to_many(roles => 'map_user_role', 'role'); -C: +C: # # Set relationships: @@ -182,10 +181,10 @@ C: # 1) Name of relationship, DBIC will create accessor with this name # 2) Name of the model class referenced by this relationship # 3) Column name in *foreign* table (aka, foreign key in peer table) - __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::Result::UserRoles', 'role_id'); + __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::Result::UserRole', 'role_id'); -C: +C: # # Set relationships: @@ -196,18 +195,17 @@ C: # 1) Name of relationship, DBIC will create accessor with this name # 2) Name of the model class referenced by this relationship # 3) Column name in *this* table - __PACKAGE__->belongs_to(user => 'MyApp::Schema::Result::Users', 'user_id'); + __PACKAGE__->belongs_to(user => 'MyApp::Schema::Result::User', 'user_id'); # belongs_to(): # args: # 1) Name of relationship, DBIC will create accessor with this name # 2) Name of the model class referenced by this relationship # 3) Column name in *this* table - __PACKAGE__->belongs_to(role => 'MyApp::Schema::Result::Roles', 'role_id'); - + __PACKAGE__->belongs_to(role => 'MyApp::Schema::Result::Role', 'role_id'); The code for these three sets of updates is obviously very similar to -the edits we made to the C, C, and C +the edits we made to the C, C, and C classes created in Chapter 3. Note that we do not need to make any change to the @@ -236,11 +234,11 @@ Look for the three new model objects in the startup debug output: | MyApp::Controller::Root | instance | | MyApp::Model::DB | instance | | MyApp::Model::DB::Author | class | - | MyApp::Model::DB::Books | class | - | MyApp::Model::DB::BookAuthors | class | - | MyApp::Model::DB::Roles | class | - | MyApp::Model::DB::Users | class | - | MyApp::Model::DB::UserRoles | class | + | MyApp::Model::DB::Book | class | + | MyApp::Model::DB::BookAuthor | class | + | MyApp::Model::DB::Role | class | + | MyApp::Model::DB::User | class | + | MyApp::Model::DB::UserRole | class | | MyApp::View::TT | instance | '-------------------------------------------------------------------+----------' ... @@ -256,17 +254,17 @@ C is new): # Load plugins use Catalyst qw/-Debug - ConfigLoader - Static::Simple + ConfigLoader + Static::Simple - StackTrace + StackTrace - Authentication + Authentication - Session - Session::Store::FastMmap - Session::State::Cookie - /; + Session + Session::Store::FastMmap + Session::State::Cookie + /; B As discussed in MoreCatalystBasics, different versions of C have used a variety of methods to load the plugins. @@ -283,6 +281,16 @@ Authentication::Store or Authentication::Credential plugin. Instead, indicate the Store and Credential you want to use in your application configuration (see below). +Make sure you include the additional plugins as new dependencies in +the Makefile.PL file something like this: + + requires ( + 'Catalyst::Plugin::Authentication' => '0', + 'Catalyst::Plugin::Session' => '0', + 'Catalyst::Plugin::Session::Store::FastMmap' => '0', + 'Catalyst::Plugin::Session::State::Cookie' => '0', + ); + Note that there are several options for L (L @@ -296,7 +304,7 @@ backed session store). =head2 Configure Authentication -There are a variety of way to provide configuration information to +There are a variety of ways to provide configuration information to L. Here we will use L @@ -308,7 +316,7 @@ C<__PACKAGE__-Esetup();>: __PACKAGE__->config->{'Plugin::Authentication'} = { default => { class => 'SimpleDB', - user_model => 'DB::Users', + user_model => 'DB::User', password_type => 'clear', }, }; @@ -328,7 +336,7 @@ to the following code: use_session 1 password_type self_check - user_model DB::Users + user_model DB::User class SimpleDB @@ -400,6 +408,9 @@ and update the definition of C to match: $c->stash->{template} = 'login.tt2'; } +Be sure to remove the C<$c-Eresponse-Ebody('Matched MyApp::Controller::Login in Login.');> +line of the C. + This controller fetches the C and C values from the login form and attempts to authenticate the user. If successful, it redirects the user to the book list page. If the login fails, the user @@ -661,7 +672,7 @@ argument: If you then open one of the Result Classes, you will see that it includes EncodedColumn in the C line. Take a look at -C since that's the main class where we +C since that's the main class where we want to use hashed and salted passwords: __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp", "EncodedColumn", "Core"); @@ -669,7 +680,7 @@ want to use hashed and salted passwords: =head2 Modify the "password" Column to Use EncodedColumn -Open the file C and enter the following +Open the file C and enter the following text below the "# DO NOT MODIFY THIS OR ANYTHING ABOVE!" line but above the closing "1;": @@ -720,7 +731,7 @@ C in your editor and enter the following text: my $schema = MyApp::Schema->connect('dbi:SQLite:myapp.db'); - my @users = $schema->resultset('Users')->all; + my @users = $schema->resultset('User')->all; foreach my $user (@users) { $user->password('mypass'); @@ -741,7 +752,7 @@ C directory for our C model. Then dump the users table to verify that it worked: - $ sqlite3 myapp.db "select * from users" + $ sqlite3 myapp.db "select * from user" 1|test01|38d3974fa9e9263099f7bc2574284b2f55473a9bM=fwpX2NR8|t01@na.com|Joe|Blow|1 2|test02|6ed8586587e53e0d7509b1cfed5df08feadc68cbMJlnPyPt0I|t02@na.com|Jane|Doe|1 3|test03|af929a151340c6aed4d54d7e2651795d1ad2e2f7UW8dHoGv9z|t03@na.com|No|Go|0 @@ -761,7 +772,7 @@ is to the C field): __PACKAGE__->config->{'Plugin::Authentication'} = { default => { class => 'SimpleDB', - user_model => 'DB::Users', + user_model => 'DB::User', password_type => 'self_check', }, }; diff --git a/lib/Catalyst/Manual/Tutorial/Authorization.pod b/lib/Catalyst/Manual/Tutorial/Authorization.pod index 7eb2a4e..fce6161 100644 --- a/lib/Catalyst/Manual/Tutorial/Authorization.pod +++ b/lib/Catalyst/Manual/Tutorial/Authorization.pod @@ -80,24 +80,32 @@ Edit C and add C to the list: # Load plugins use Catalyst qw/-Debug - ConfigLoader - Static::Simple + ConfigLoader + Static::Simple - StackTrace + StackTrace - Authentication - Authorization::Roles + Authentication + Authorization::Roles - Session - Session::Store::FastMmap - Session::State::Cookie - /; + Session + Session::Store::FastMmap + Session::State::Cookie + /; B As discussed in MoreCatalystBasics, different versions of C have used a variety of methods to load the plugins. You can put the plugins in the C statement if you prefer. +Once again (remain sharp, by now you should be getting the hang of things) +include this additional plugin as a new dependency in the Makefile.PL file +like this: + + requires ( + ... + 'Catalyst::Plugin::Authorization::Roles' => '0', + ); =head2 Add Role-Specific Logic to the "Book List" Template @@ -109,7 +117,7 @@ lines to the bottom of the file:
    [% # Dump list of roles -%] - [% FOR role = c.user.roles %]
  • [% role %]
  • [% END %] + [% FOR role = c.user.role %]
  • [% role %]
  • [% END %]

@@ -160,16 +168,16 @@ updating C to match the following code: if ($c->check_user_roles('admin')) { # Call create() on the book model object. Pass the table # columns/field values we want to set as hash values - my $book = $c->model('DB::Books')->create({ + my $book = $c->model('DB::Book')->create({ title => $title, rating => $rating }); # Add a record to the join table for this book, mapping to # appropriate author - $book->add_to_book_authors({author_id => $author_id}); + $book->add_to_book_author({author_id => $author_id}); # Note: Above is a shortcut for this: - # $book->create_related('book_authors', {author_id => $author_id}); + # $book->create_related('book_author', {author_id => $author_id}); # Assign the Book object to the stash for display in the view $c->stash->{book} = $book; @@ -236,7 +244,7 @@ your controllers and views be an "thin" as possible, with all of the For example, let's add a method to our C Result Class to check if a user is allowed to delete a book. Open -C and add the following method +C and add the following method (be sure to add it below the "C" line): =head2 delete_allowed_by @@ -254,7 +262,7 @@ C and add the following method Here we call a C method on our user object, so we should add this method to our Result Class. Open -C and add the following method below +C and add the following method below the "C" line: =head 2 has_role diff --git a/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod b/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod index 3eb6830..463e8d5 100644 --- a/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod +++ b/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod @@ -105,16 +105,16 @@ Edit C and enter the following method: # Call create() on the book model object. Pass the table # columns/field values we want to set as hash values - my $book = $c->model('DB::Books')->create({ + my $book = $c->model('DB::Book')->create({ title => $title, rating => $rating }); # Add a record to the join table for this book, mapping to # appropriate author - $book->add_to_book_authors({author_id => $author_id}); + $book->add_to_book_author({author_id => $author_id}); # Note: Above is a shortcut for this: - # $book->create_related('book_authors', {author_id => $author_id}); + # $book->create_related('book_author', {author_id => $author_id}); # Assign the Book object to the stash for display in the view $c->stash->{book} = $book; @@ -127,7 +127,7 @@ Notice that Catalyst takes "extra slash-separated information" from the URL and passes it as arguments in C<@_>. The C action then uses a simple call to the DBIC C method to add the requested information to the database (with a separate call to -C to update the join table). As do virtually all +C to update the join table). As do virtually all controller methods (at least the ones that directly handle user input), it then sets the template that should handle this request. @@ -153,8 +153,8 @@ Edit C and then enter: [% # Output the last name of the first author. This is complicated by an -%] [% # issue in TT 2.15 where blessed hash objects are not handled right. -%] - [% # First, fetch 'book.authors' from the DB once. -%] - [% authors = book.authors %] + [% # First, fetch 'book.author' from the DB once. -%] + [% authors = book.author %] [% # Now use IF statements to test if 'authors.first' is "working". If so, -%] [% # we use it. Otherwise we use a hack that seems to keep TT 2.15 happy. -%] by '[% authors.first.last_name IF authors.first; @@ -208,11 +208,8 @@ object as it was returned by DBIC. You should also see the following DBIC debug messages displayed in the development server log messages if you have DBIC_TRACE set: - INSERT INTO books (rating, title) VALUES (?, ?): `5', `TCPIP_Illustrated_Vol-2' - INSERT INTO book_authors (author_id, book_id) VALUES (?, ?): `4', `6' - SELECT author.id, author.first_name, author.last_name - FROM book_authors me JOIN authors author - ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '6' + INSERT INTO book (rating, title) VALUES (?, ?): `5', `TCPIP_Illustrated_Vol-2' + INSERT INTO book_author (author_id, book_id) VALUES (?, ?): `4', `6' The C statements are obviously adding the book and linking it to the existing record for Richard Stevens. The C