[Catalyst-commits] r10275 - in
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial: .
AdvancedCRUD
hkclark at dev.catalyst.perl.org
hkclark at dev.catalyst.perl.org
Sun May 24 22:06:59 GMT 2009
Author: hkclark
Date: 2009-05-24 22:06:59 +0000 (Sun, 24 May 2009)
New Revision: 10275
Modified:
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod
Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod
Log:
Merge from depluralization branch
Modified: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod 2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod 2009-05-24 22:06:59 UTC (rev 10275)
@@ -132,7 +132,7 @@
# 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 @@
$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 @@
Login as C<test01> (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 @@
$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) {
Modified: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod 2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod 2009-05-24 22:06:59 UTC (rev 10275)
@@ -82,9 +82,9 @@
C<myapp02.sql> 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 @@
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 @@
--
-- Load up some initial test data
--
- INSERT INTO users VALUES (1, 'test01', 'mypass', 't01 at na.com', 'Joe', 'Blow', 1);
- INSERT INTO users VALUES (2, 'test02', 'mypass', 't02 at na.com', 'Jane', 'Doe', 1);
- INSERT INTO users VALUES (3, 'test03', 'mypass', 't03 at 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 at na.com', 'Joe', 'Blow', 1);
+ INSERT INTO user VALUES (2, 'test02', 'mypass', 't02 at na.com', 'Jane', 'Doe', 1);
+ INSERT INTO user VALUES (3, 'test03', 'mypass', 't03 at 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<myapp.db> 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 @@
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<lib/MyApp/Schema/Result> directory. And, more
@@ -144,12 +143,12 @@
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<lib/MyApp/Schema/Result/Users.pm>:
+C<lib/MyApp/Schema/Result/User.pm>:
#
# Set relationships:
@@ -160,7 +159,7 @@
# 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 @@
__PACKAGE__->many_to_many(roles => 'map_user_role', 'role');
-C<lib/MyApp/Schema/Result/Roles.pm>:
+C<lib/MyApp/Schema/Result/Role.pm>:
#
# Set relationships:
@@ -182,10 +181,10 @@
# 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<lib/MyApp/Schema/Result/UserRoles.pm>:
+C<lib/MyApp/Schema/Result/UserRole.pm>:
#
# Set relationships:
@@ -196,18 +195,17 @@
# 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<Books>, C<Authors>, and C<BookAuthors>
+the edits we made to the C<Book>, C<Author>, and C<BookAuthor>
classes created in Chapter 3.
Note that we do not need to make any change to the
@@ -236,11 +234,11 @@
| 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 @@
# 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<Note:> As discussed in MoreCatalystBasics, different versions of
C<Catalyst::Devel> have used a variety of methods to load the plugins.
@@ -283,6 +281,16 @@
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<Session::Store|Catalyst::Plugin::Session::Store>
(L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap>
@@ -296,7 +304,7 @@
=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<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>.
Here we will use
L<Catalyst::Authentication::Realm::SimpleDB|Catalyst::Authentication::Realm::SimpleDB>
@@ -308,7 +316,7 @@
__PACKAGE__->config->{'Plugin::Authentication'} = {
default => {
class => 'SimpleDB',
- user_model => 'DB::Users',
+ user_model => 'DB::User',
password_type => 'clear',
},
};
@@ -328,7 +336,7 @@
use_session 1
<default>
password_type self_check
- user_model DB::Users
+ user_model DB::User
class SimpleDB
</default>
</Plugin::Authentication>
@@ -400,6 +408,9 @@
$c->stash->{template} = 'login.tt2';
}
+Be sure to remove the C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Login in Login.');>
+line of the C<sub index>.
+
This controller fetches the C<username> and C<password> 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 @@
If you then open one of the Result Classes, you will see that it
includes EncodedColumn in the C<load_components> line. Take a look at
-C<lib/MyApp/Schema/Result/Users.pm> since that's the main class where we
+C<lib/MyApp/Schema/Result/User.pm> 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 @@
=head2 Modify the "password" Column to Use EncodedColumn
-Open the file C<lib/MyApp/Schema/Result/Users.pm> and enter the following
+Open the file C<lib/MyApp/Schema/Result/User.pm> and enter the following
text below the "# DO NOT MODIFY THIS OR ANYTHING ABOVE!" line but above
the closing "1;":
@@ -720,7 +731,7 @@
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 @@
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 at na.com|Joe|Blow|1
2|test02|6ed8586587e53e0d7509b1cfed5df08feadc68cbMJlnPyPt0I|t02 at na.com|Jane|Doe|1
3|test03|af929a151340c6aed4d54d7e2651795d1ad2e2f7UW8dHoGv9z|t03 at na.com|No|Go|0
@@ -761,7 +772,7 @@
__PACKAGE__->config->{'Plugin::Authentication'} = {
default => {
class => 'SimpleDB',
- user_model => 'DB::Users',
+ user_model => 'DB::User',
password_type => 'self_check',
},
};
Modified: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod 2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod 2009-05-24 22:06:59 UTC (rev 10275)
@@ -80,25 +80,33 @@
# 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<Note:> As discussed in MoreCatalystBasics, different versions of
C<Catalyst::Devel> have used a variety of methods to load the plugins.
You can put the plugins in the C<use Catalyst> 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
Open C<root/src/books/list.tt2> in your editor and add the following
@@ -109,7 +117,7 @@
<ul>
[% # Dump list of roles -%]
- [% FOR role = c.user.roles %]<li>[% role %]</li>[% END %]
+ [% FOR role = c.user.role %]<li>[% role %]</li>[% END %]
</ul>
<p>
@@ -160,16 +168,16 @@
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 @@
For example, let's add a method to our C<Books.pm> Result Class to
check if a user is allowed to delete a book. Open
-C<lib/MyApp/Schema/Result/Books.pm> and add the following method
+C<lib/MyApp/Schema/Result/Book.pm> and add the following method
(be sure to add it below the "C<DO NOT MODIFY ...>" line):
=head2 delete_allowed_by
@@ -254,7 +262,7 @@
Here we call a C<has_role> method on our user object, so we should add
this method to our Result Class. Open
-C<lib/MyApp/Schema/Result/Users.pm> and add the following method below
+C<lib/MyApp/Schema/Result/User.pm> and add the following method below
the "C<DO NOT MODIFY ...>" line:
=head 2 has_role
Modified: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod 2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod 2009-05-24 22:06:59 UTC (rev 10275)
@@ -105,16 +105,16 @@
# 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 @@
URL and passes it as arguments in C<@_>. The C<url_create> action then
uses a simple call to the DBIC C<create> method to add the requested
information to the database (with a separate call to
-C<add_to_book_authors> to update the join table). As do virtually all
+C<add_to_book_author> 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 @@
[% # 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 @@
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<INSERT> statements are obviously adding the book and linking it to
the existing record for Richard Stevens. The C<SELECT> statement results
@@ -220,9 +217,14 @@
If you then click the "Return to list" link, you should find that
there are now six books shown (if necessary, Shift+Reload or
-Ctrl+Reload your browser at the C</books/list> page).
+Ctrl+Reload your browser at the C</books/list> page). You should now see
+the following six DBIC debug messages displayed for N=1-6:
+ SELECT author.id, author.first_name, author.last_name \
+ FROM book_author me JOIN author author \
+ ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): 'N'
+
=head1 CONVERT TO A CHAINED ACTION
Although the example above uses the same C<Local> action type for the
@@ -400,7 +402,7 @@
my ($self, $c) = @_;
# Store the ResultSet in stash so it's available for other methods
- $c->stash->{resultset} = $c->model('DB::Books');
+ $c->stash->{resultset} = $c->model('DB::Book');
# Print a message to the debug log
$c->log->debug('*** INSIDE BASE METHOD ***');
@@ -516,12 +518,12 @@
my $author_id = $c->request->params->{author_id} || '1';
# Create the book
- my $book = $c->model('DB::Books')->create({
+ my $book = $c->model('DB::Book')->create({
title => $title,
rating => $rating,
});
# Handle relationship with author
- $book->add_to_book_authors({author_id => $author_id});
+ $book->add_to_book_author({author_id => $author_id});
# Store new model object in stash
$c->stash->{book} = $book;
@@ -602,14 +604,15 @@
[% # authors into the list. Note that the 'push' TT vmethod doesn't return -%]
[% # a value, so nothing will be printed here. But, if you have something -%]
[% # in TT that does return a value and you don't want it printed, you can -%]
- [% # 1) assign it to a bogus value, or -%]
- [% # 2) use the CALL keyword to call it and discard the return value. -%]
+ [% # 1) assign it to a bogus value, or # 2) use the CALL keyword to -%]
+ [% # call it and discard the return value. -%]
[% tt_authors = [ ];
- tt_authors.push(author.last_name) FOREACH author = book.authors %]
+ tt_authors.push(author.last_name) FOREACH author = book.author %]
[% # Now use a TT 'virtual method' to display the author count in parens -%]
- ([% tt_authors.size %])
+ [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
+ ([% tt_authors.size | html %])
[% # Use another TT vmethod to join & print the names & comma separators -%]
- [% tt_authors.join(', ') %]
+ [% tt_authors.join(', ') | html %]
</td>
<td>
[% # Add a link to delete a book %]
@@ -729,7 +732,7 @@
my ($self, $c) = @_;
# Use the book object saved by 'object' and delete it along
- # with related 'book_authors' entries
+ # with related 'book_author' entries
$c->stash->{object}->delete;
# Set a status message to be displayed at the top of the view
@@ -741,7 +744,7 @@
This method first deletes the book object saved by the C<object> method.
However, it also removes the corresponding entry from the
-C<book_authors> table with a cascading delete.
+C<book_author> table with a cascading delete.
Then, rather than forwarding to a "delete done" page as we did with the
earlier create example, it simply sets the C<status_msg> to display a
@@ -785,10 +788,10 @@
along with a list of the eight remaining books. You will also see the
cascading delete operation via the DBIC_TRACE output:
- SELECT me.id, me.title, me.rating FROM books me WHERE ( ( me.id = ? ) ): '6'
- DELETE FROM books WHERE ( id = ? ): '6'
- SELECT me.book_id, me.author_id FROM book_authors me WHERE ( me.book_id = ? ): '6'
- DELETE FROM book_authors WHERE ( author_id = ? AND book_id = ? ): '4', '6'
+ SELECT me.id, me.title, me.rating FROM book me WHERE ( ( me.id = ? ) ): '6'
+ DELETE FROM book WHERE ( id = ? ): '6'
+ SELECT me.book_id, me.author_id FROM book_author me WHERE ( me.book_id = ? ): '6'
+ DELETE FROM book_author WHERE ( author_id = ? AND book_id = ? ): '4', '6'
=head2 Fixing a Dangerous URL
@@ -825,7 +828,7 @@
my ($self, $c) = @_;
# Use the book object saved by 'object' and delete it along
- # with related 'book_authors' entries
+ # with related 'book_author' entries
$c->stash->{object}->delete;
# Set a status message to be displayed at the top of the view
@@ -870,7 +873,7 @@
my ($self, $c) = @_;
# Use the book object saved by 'object' and delete it along
- # with related 'book_authors' entries
+ # with related 'book_author' entries
$c->stash->{object}->delete;
# Redirect the user back to the list page with status msg as an arg
@@ -936,10 +939,10 @@
each book was added and when each book is updated:
$ sqlite3 myapp.db
- sqlite> ALTER TABLE books ADD created INTEGER;
- sqlite> ALTER TABLE books ADD updated INTEGER;
- sqlite> UPDATE books SET created = DATETIME('NOW'), updated = DATETIME('NOW');
- sqlite> SELECT * FROM books;
+ sqlite> ALTER TABLE book ADD created INTEGER;
+ sqlite> ALTER TABLE book ADD updated INTEGER;
+ sqlite> UPDATE book SET created = DATETIME('NOW'), updated = DATETIME('NOW');
+ sqlite> SELECT * FROM book;
1|CCSP SNRS Exam Certification Guide|5|2009-03-08 16:26:35|2009-03-08 16:26:35
2|TCP/IP Illustrated, Volume 1|5|2009-03-08 16:26:35|2009-03-08 16:26:35
3|Internetworking with TCP/IP Vol.1|4|2009-03-08 16:26:35|2009-03-08 16:26:35
@@ -970,7 +973,7 @@
it to include the L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp>
in the C<load_components> line of the Result Classes.
-If you open C<lib/MyApp/Schema/Result/Books.pm> in your editor you
+If you open C<lib/MyApp/Schema/Result/Book.pm> in your editor you
should see that the C<created> and C<updated> fields are now included
in the call to C<add_columns()>, but our relationship information below
the "C<# DO NOT MODIFY...>" line was automatically preserved.
@@ -1011,7 +1014,7 @@
you will see that the new book we added has an appropriate date and
time entered for it (see the last line in the listing below):
- sqlite3 myapp.db "select * from books"
+ sqlite3 myapp.db "select * from book"
1|CCSP SNRS Exam Certification Guide|5|2009-03-08 16:26:35|2009-03-08 16:26:35
2|TCP/IP Illustrated, Volume 1|5|2009-03-08 16:26:35|2009-03-08 16:26:35
3|Internetworking with TCP/IP Vol.1|4|2009-03-08 16:26:35|2009-03-08 16:26:35
@@ -1023,9 +1026,9 @@
Notice in the debug log that the SQL DBIC generated has changed to
incorporate the datetime logic:
- INSERT INTO books (created, rating, title, updated) VALUES (?, ?, ?, ?):
+ INSERT INTO book (created, rating, title, updated) VALUES (?, ?, ?, ?):
'2009-03-08 16:29:08', '5', 'TCPIP_Illustrated_Vol-2', '2009-03-08 16:29:08'
- INSERT INTO book_authors (author_id, book_id) VALUES (?, ?): '4', '10'
+ INSERT INTO book_author (author_id, book_id) VALUES (?, ?): '4', '10'
=head2 Create a ResultSet Class
@@ -1044,9 +1047,9 @@
mkdir lib/MyApp/Schema/ResultSet
-Then open C<lib/MyApp/Schema/ResultSet/Books.pm> and enter the following:
+Then open C<lib/MyApp/Schema/ResultSet/Book.pm> and enter the following:
- package MyApp::Schema::ResultSet::Books;
+ package MyApp::Schema::ResultSet::Book;
use strict;
use warnings;
@@ -1072,13 +1075,13 @@
1;
Then we need to tell the Result Class to to treat this as a ResultSet
-Class. Open C<lib/MyApp/Schema/Result/Books.pm> and add the following
+Class. Open C<lib/MyApp/Schema/Result/Book.pm> and add the following
above the "C<1;>" at the bottom of the file:
#
# Set ResultSet Class
#
- __PACKAGE__->resultset_class('MyApp::Schema::ResultSet::Books');
+ __PACKAGE__->resultset_class('MyApp::Schema::ResultSet::Book');
Then add the following method to the C<lib/MyApp/Controller/Books.pm>:
@@ -1094,7 +1097,7 @@
# Retrieve all of the book records as book model objects and store in the
# stash where they can be accessed by the TT template, but only
# retrieve books created within the last $min number of minutes
- $c->stash->{books} = [$c->model('DB::Books')
+ $c->stash->{books} = [$c->model('DB::Book')
->created_after(DateTime->now->subtract(minutes => $mins))];
# Set the TT template to use. You will almost always want to do this
@@ -1144,7 +1147,7 @@
# stash where they can be accessed by the TT template, but only
# retrieve books created within the last $min number of minutes
# AND that have 'TCP' in the title
- $c->stash->{books} = [$c->model('DB::Books')
+ $c->stash->{books} = [$c->model('DB::Book')
->created_after(DateTime->now->subtract(minutes => $mins))
->search({title => {'like', '%TCP%'}})
];
@@ -1174,13 +1177,13 @@
Take a look at the DBIC_TRACE output in the development server log for
the first URL and you should see something similar to the following:
- SELECT me.id, me.title, me.rating, me.created, me.updated FROM books me
+ SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me
WHERE ( ( ( title LIKE ? ) AND ( created > ? ) ) ): '%TCP%', '2009-03-08 14:52:54'
However, let's not pollute our controller code with this raw "TCP"
query -- it would be cleaner to encapsulate that code in a method on
our ResultSet Class. To do this, open
-C<lib/MyApp/Schema/ResultSet/Books.pm> and add the following method:
+C<lib/MyApp/Schema/ResultSet/Book.pm> and add the following method:
=head2 title_like
@@ -1215,7 +1218,7 @@
# stash where they can be accessed by the TT template, but only
# retrieve books created within the last $min number of minutes
# AND that have 'TCP' in the title
- $c->stash->{books} = [$c->model('DB::Books')
+ $c->stash->{books} = [$c->model('DB::Book')
->created_after(DateTime->now->subtract(minutes => $mins))
->title_like('TCP')
];
@@ -1242,7 +1245,7 @@
to an entire query, the Result Class construct is used to represent a
row. Therefore, we can add row-specific "helper methods" to our Result
Classes stored in C<lib/MyApp/Schema/Result/>. For example, open
-C<lib/MyApp/Schema/Result/Authors.pm> and add the following method (as
+C<lib/MyApp/Schema/Result/Author.pm> and add the following method (as
always, it must be above the closing "C<1;>"):
#
@@ -1260,14 +1263,14 @@
...
[% tt_authors = [ ];
- tt_authors.push(author.last_name) FOREACH author = book.authors %]
+ tt_authors.push(author.last_name) FOREACH author = book.author %]
...
to:
...
[% tt_authors = [ ];
- tt_authors.push(author.full_name) FOREACH author = book.authors %]
+ tt_authors.push(author.full_name) FOREACH author = book.author %]
...
(Only C<author.last_name> was changed to C<author.full_name> -- the
Modified: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod 2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod 2009-05-24 22:06:59 UTC (rev 10275)
@@ -219,7 +219,7 @@
| / | /index |
'-------------------------------------+--------------------------------------'
- [info] Hello powered by Catalyst 5.71000
+ [info] Hello powered by Catalyst 5.80003
You can connect to your server at http://debian:3000
Point your web browser to L<http://localhost:3000> (substituting a
Modified: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod 2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod 2009-05-24 22:06:59 UTC (rev 10275)
@@ -128,7 +128,7 @@
# Retrieve all of the book records as book model objects and store in the
# stash where they can be accessed by the TT template
- $c->stash->{books} = [$c->model('DB::Books')->all];
+ $c->stash->{books} = [$c->model('DB::Book')->all];
# Set the TT template to use. You will almost always want to do this
# in your action methods.
@@ -140,6 +140,10 @@
B<NOTE:> The C<DB> here is the Perl Debugger, not the DB model.
+If you haven't done it already, enable SQL logging as before:
+
+ $ export DBIC_TRACE=1
+
To now run the Catalyst development server under the Perl debugger, simply
prepend C<perl -d> to the front of C<script/myapp_server.pl>:
@@ -169,7 +173,7 @@
development server will drop to the Perl debugger prompt:
MyApp::Controller::Books::list(/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm:48):
- 48: $c->stash->{books} = [$c->model('DB::Books')->all];
+ 48: $c->stash->{books} = [$c->model('DB::Book')->all];
DB<1>
@@ -179,7 +183,7 @@
C<single-step> into methods/subroutines):
DB<1> n
- SELECT me.id, me.authors, me.title, me.rating FROM books me:
+ SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me:
MyApp::Controller::Books::list(/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm:53):
53: $c->stash->{template} = 'books/list.tt2';
@@ -191,12 +195,14 @@
Next, list the methods available on our C<Book> model:
- DB<1> m $c->model('DB::Books')
+ DB<1> m $c->model('DB::Book')
()
(0+
(bool
+ __result_class_accessor
__source_handle_accessor
_add_alias
+ __bool
_build_unique_query
_calculate_score
_collapse_cond
@@ -206,8 +212,8 @@
We can also play with the model directly:
- DB<2> x ($c->model('DB::Books')->all)[1]->title
- SELECT me.id, me.title, me.rating FROM books me:
+ DB<2> x ($c->model('DB::Book')->all)[1]->title
+ SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me:
0 'TCP/IP Illustrated, Volume 1'
This uses the Perl debugger C<x> command to display the title of a book.
@@ -219,9 +225,11 @@
0 ARRAY(0xa8f3b7c)
0 MyApp::Model::DB::Book=HASH(0xb8e702c)
'_column_data' => HASH(0xb8e5e2c)
+ 'created' => '2009-05-08 10:19:46'
'id' => 1
'rating' => 5
'title' => 'CCSP SNRS Exam Certification Guide'
+ 'updated' => '2009-05-08 10:19:46'
'_in_storage' => 1
<lines removed for brevity>
@@ -233,17 +241,33 @@
Finally, press C<Ctrl+C> to break out of the development server.
Because we are running inside the Perl debugger, you will drop to the
-debugger prompt. Press C<q> to exit the debugger and return to your OS
+debugger prompt.
+
+ ^CCatalyst::Engine::HTTP::run(/usr/local/share/perl/5.10.0/Catalyst/Engine/HTTP.pm:260):
+ 260: while ( accept( Remote, $daemon ) ) {
+
+ DB<4>
+
+Finally, press C<q> to exit the debugger and return to your OS
shell prompt:
DB<4> q
$
For more information on using the Perl debugger, please see C<perldebug>
-and C<perldebtut>. You can also type C<h> or C<h h> at the debugger
-prompt to view the built-in help screens.
+and C<perldebtut>. For those daring souls out there, you can dive down
+even deeper into the magical depths of this fine debugger by checking
+out C<perldebguts>.
+You can also type C<h> or C<h h> at the debugger prompt to view the
+built-in help screens.
+For an excellent book covering all aspects of the Perl debugger, we highly
+recommend reading 'Pro Perl Debugging' by Richard Foley.
+
+Oh yeah, before you forget, be sure to remove the C<DB::single=1> line you
+added above in C<lib/MyApp/Controller/Books.pm>.
+
=head1 DEBUGGING MODULES FROM CPAN
Although the techniques discussed above work well for code you are
@@ -264,9 +288,9 @@
mkdir -p lib/Module; cp `perldoc -l Module::Name` lib/Module/
-Note: If you are following along in Debian 5, you will need to install
-the C<perl-doc> package to use the C<perldoc> command. Use
-C<sudo aptitude install perl-doc> to do that.
+Note: If you are following along in Debian 5 or Ubuntu, you will
+need to install the C<perl-doc> package to use the C<perldoc> command.
+Use C<sudo aptitude install perl-doc> to do that.
For example, you could make a copy of
L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
@@ -295,6 +319,12 @@
'print $Catalyst::Plugin::Authentication::VERSION;'
0.07
+and if you are using bash aliases:
+
+ alias pmver="perl -le '\$m = shift; eval qq(require \$m) \
+ or die qq(module \"\$m\" is not installed\\n); \
+ print \$m->VERSION'"
+
=item *
Check if a modules contains a given method:
@@ -336,6 +366,7 @@
enabled will conflict with several of the conventions used by this
tutorial to leave some variables undefined on purpose).
+Happy debugging.
=head1 AUTHOR
Modified: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod 2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod 2009-05-24 22:06:59 UTC (rev 10275)
@@ -190,11 +190,11 @@
# Load plugins
use Catalyst qw/-Debug
- ConfigLoader
- Static::Simple
+ ConfigLoader
+ Static::Simple
- StackTrace
- /;
+ StackTrace
+ /;
B<Note:> Recent versions of C<Catalyst::Devel> have used a variety of
techniques to load these plugins/flags. For example, you might see
@@ -213,6 +213,14 @@
browser, not in the console window from which you're running your
application, which is where logging output usually goes.
+Make sure that when adding new plugins that you include them as a new
+dependancies within the Makefile.PL file. For example, after adding
+the StackTrace plugin the Makefile.PL should include the following
+line:
+
+ requires 'Catalyst::Plugin::StackTrace';
+
+
B<Notes:>
=over 4
@@ -273,7 +281,7 @@
# Retrieve all of the book records as book model objects and store in the
# stash where they can be accessed by the TT template
- # $c->stash->{books} = [$c->model('DB::Books')->all];
+ # $c->stash->{books} = [$c->model('DB::Book')->all];
# But, for now, use this code until we create the model later
$c->stash->{books} = '';
@@ -559,18 +567,18 @@
--
-- Create a very simple database to hold book and author information
--
- CREATE TABLE books (
+ CREATE TABLE book (
id INTEGER PRIMARY KEY,
title TEXT ,
rating INTEGER
);
- -- 'book_authors' is a many-to-many join table between books & authors
- CREATE TABLE book_authors (
+ -- 'book_author' is a many-to-many join table between books & authors
+ CREATE TABLE book_author (
book_id INTEGER,
author_id INTEGER,
PRIMARY KEY (book_id, author_id)
);
- CREATE TABLE authors (
+ CREATE TABLE author (
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT
@@ -578,27 +586,27 @@
---
--- Load some sample data
---
- INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
- INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
- INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
- INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
- INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
- INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
- INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
- INSERT INTO authors VALUES (3, 'Christian', 'Degu');
- INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
- INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
- INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
- INSERT INTO authors VALUES (7, 'Nathan', 'Torkington');
- INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
- INSERT INTO book_authors VALUES (1, 1);
- INSERT INTO book_authors VALUES (1, 2);
- INSERT INTO book_authors VALUES (1, 3);
- INSERT INTO book_authors VALUES (2, 4);
- INSERT INTO book_authors VALUES (3, 5);
- INSERT INTO book_authors VALUES (4, 6);
- INSERT INTO book_authors VALUES (4, 7);
- INSERT INTO book_authors VALUES (5, 8);
+ INSERT INTO book VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
+ INSERT INTO book VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
+ INSERT INTO book VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
+ INSERT INTO book VALUES (4, 'Perl Cookbook', 5);
+ INSERT INTO book VALUES (5, 'Designing with Web Standards', 5);
+ INSERT INTO author VALUES (1, 'Greg', 'Bastien');
+ INSERT INTO author VALUES (2, 'Sara', 'Nasseh');
+ INSERT INTO author VALUES (3, 'Christian', 'Degu');
+ INSERT INTO author VALUES (4, 'Richard', 'Stevens');
+ INSERT INTO author VALUES (5, 'Douglas', 'Comer');
+ INSERT INTO author VALUES (6, 'Tom', 'Christiansen');
+ INSERT INTO author VALUES (7, 'Nathan', 'Torkington');
+ INSERT INTO author VALUES (8, 'Jeffrey', 'Zeldman');
+ INSERT INTO book_author VALUES (1, 1);
+ INSERT INTO book_author VALUES (1, 2);
+ INSERT INTO book_author VALUES (1, 3);
+ INSERT INTO book_author VALUES (2, 4);
+ INSERT INTO book_author VALUES (3, 5);
+ INSERT INTO book_author VALUES (4, 6);
+ INSERT INTO book_author VALUES (4, 7);
+ INSERT INTO book_author VALUES (5, 8);
Then use the following command to build a C<myapp.db> SQLite database:
@@ -615,7 +623,7 @@
$ sqlite3 myapp.db
SQLite version 3.5.9
Enter ".help" for instructions
- sqlite> select * from books;
+ sqlite> select * from book;
1|CCSP SNRS Exam Certification Guide|5
2|TCP/IP Illustrated, Volume 1|5
3|Internetworking with TCP/IP Vol.1|4
@@ -626,7 +634,7 @@
Or:
- $ sqlite3 myapp.db "select * from books"
+ $ sqlite3 myapp.db "select * from book"
1|CCSP SNRS Exam Certification Guide|5
2|TCP/IP Illustrated, Volume 1|5
3|Internetworking with TCP/IP Vol.1|4
@@ -639,6 +647,15 @@
".q" to exit from SQLite from the SQLite interactive mode and return to
your OS command prompt.
+Please note that here we have chosen to use 'singular' table names. This
+is because the default inflection code for L<DBIx::Class:Schema::Loader>
+does NOT handle plurals. There has been much philosophical discussion
+on whether table names should be plural or singular. There is no one
+correct answer, as long as one makes a choice and remains consistent
+with it. If you prefer plural table names (e.g. they are easier and
+more natural to read) then you will need to pass it an inflect_map
+option. See L<DBIx::Class:Schema::Loader> for more information.
+
For using other databases, such as PostgreSQL or MySQL, see
L<Appendix 2|Catalyst::Manual::Tutorial::Appendices>.
@@ -675,6 +692,9 @@
'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
0.23
+(please note that the '\' above is a line continuation marker and
+should NOT be included as part of the command)
+
If you don't have version 0.23 or higher, please run this command
to install it directly from CPAN:
@@ -701,6 +721,9 @@
created "/home/me/MyApp/script/../lib/MyApp/Model/DB.pm"
created "/home/me/MyApp/script/../t/model_DB.t"
+(please note that the '\' above is a line continuation marker and
+should NOT be included as part of the command)
+
The C<script/myapp_create.pl> command breaks down like this:
=over 4
@@ -743,7 +766,7 @@
find that C<lib/MyApp> contains a C<Schema> subdirectory, which then
has a subdirectory called "Result". This "Result" subdirectory then
has files named according to each of the tables in our simple database
-(C<Authors.pm>, C<BookAuthors.pm>, and C<Books.pm>). These three
+(C<Author.pm>, C<BookAuthor.pm>, and C<Book.pm>). These three
files are called "Result Classes" in DBIx::Class nomenclature. Although the
Result Class files are named after tables in our database, the classes
correspond to the I<row-level data> that is returned by DBIC (more on
@@ -785,6 +808,10 @@
$ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
create=static components=TimeStamp dbi:SQLite:myapp.db
$
+ $ # Note that the '\' above is a line continuation marker and
+ $ # should NOT be included as part of the command
+
+ $
$ # Now convert the existing files over
$ cd lib/MyApp/Schema
$ perl -MIO::All -e 'for (@ARGV) { my $s < io($_); $s =~ s/.*\n\# You can replace.*?\n//s;
@@ -806,7 +833,7 @@
Open C<lib/MyApp/Controller/Books.pm> and un-comment the model code we
left disabled earlier so that your version matches the following (un-
-comment the line containing C<[$c-E<gt>model('DB::Books')-E<gt>all]>
+comment the line containing C<[$c-E<gt>model('DB::Book')-E<gt>all]>
and delete the next 2 lines):
=head2 list
@@ -823,7 +850,7 @@
# Retrieve all of the book records as book model objects and store in the
# stash where they can be accessed by the TT template
- $c->stash->{books} = [$c->model('DB::Books')->all];
+ $c->stash->{books} = [$c->model('DB::Book')->all];
# Set the TT template to use. You will almost always want to do this
# in your action methods (action methods respond to user input in
@@ -831,8 +858,8 @@
$c->stash->{template} = 'books/list.tt2';
}
-B<TIP>: You may see the C<$c-E<gt>model('DB::Books')> un-commented
-above written as C<$c-E<gt>model('DB')-E<gt>resultset('Books')>. The
+B<TIP>: You may see the C<$c-E<gt>model('DB::Book')> un-commented
+above written as C<$c-E<gt>model('DB')-E<gt>resultset('Book')>. The
two are equivalent. Either way, C<$c-E<gt>model> returns a
L<DBIx::Class::ResultSet|DBIx::Class::ResultSet> which handles queries
against the database and iterating over the set of results that is
@@ -843,7 +870,7 @@
things like filtering and sorting the results. For example, the
following could be used to sort the results by descending title:
- $c->model('DB::Books')->search({}, {order_by => 'title DESC'});
+ $c->model('DB::Book')->search({}, {order_by => 'title DESC'});
Some other examples are provided in
L<DBIx::Class::Manual::Cookbook/Complex WHERE clauses>, with
@@ -880,9 +907,9 @@
[debug] Statistics enabled
[debug] Loaded plugins:
.----------------------------------------------------------------------------.
- | Catalyst::Plugin::ConfigLoader 0.20 |
- | Catalyst::Plugin::StackTrace 0.08 |
- | Catalyst::Plugin::Static::Simple 0.20 |
+ | Catalyst::Plugin::ConfigLoader 0.23 |
+ | Catalyst::Plugin::StackTrace 0.10 |
+ | Catalyst::Plugin::Static::Simple 0.21 |
'----------------------------------------------------------------------------'
[debug] Loaded dispatcher "Catalyst::Dispatcher"
@@ -896,9 +923,9 @@
| MyApp::Controller::Books | instance |
| MyApp::Controller::Root | instance |
| MyApp::Model::DB | instance |
- | MyApp::Model::DB::Authors | class |
- | MyApp::Model::DB::BookAuthors | class |
- | MyApp::Model::DB::Books | class |
+ | MyApp::Model::DB::Author | class |
+ | MyApp::Model::DB::Book | class |
+ | MyApp::Model::DB::BookAuthor | class |
| MyApp::View::TT | instance |
'-----------------------------------------------------------------+----------'
@@ -923,7 +950,7 @@
| /books/list | /books/list |
'-------------------------------------+--------------------------------------'
- [info] MyApp powered by Catalyst 5.71000
+ [info] MyApp powered by Catalyst 5.80003
You can connect to your server at http://debian:3000
B<NOTE:> Be sure you run the C<script/myapp_server.pl> command from
@@ -941,8 +968,8 @@
Catalyst::Model::DBIC::Schema dynamically created three model classes,
one to represent each of the three tables in our database
-(C<MyApp::Model::DB::Authors>, C<MyApp::Model::DB::BookAuthors>,
-and C<MyApp::Model::DB::Books>).
+(C<MyApp::Model::DB::Author>, C<MyApp::Model::DB::BookAuthor>,
+and C<MyApp::Model::DB::Book>).
=item *
@@ -1151,7 +1178,7 @@
Result Class files. (Note: if you are using a database other than
SQLite, such as PostgreSQL, then the relationship could have been
automatically placed in the Result Class files. If so, you can skip
-this step.) First edit C<lib/MyApp/Schema/Result/Books.pm> and add the
+this step.) First edit C<lib/MyApp/Schema/Result/Book.pm> and add the
following text below the C<# You can replace this text...> comment:
#
@@ -1163,7 +1190,7 @@
# 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(book_authors => 'MyApp::Schema::Result::BookAuthors', 'book_id');
+ __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'book_id');
# many_to_many():
# args:
@@ -1171,7 +1198,7 @@
# 2) Name of has_many() relationship this many_to_many() is shortcut for
# 3) Name of belongs_to() relationship in model class of has_many() above
# You must already have the has_many() defined to use a many_to_many().
- __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
+ __PACKAGE__->many_to_many(author => 'book_author', 'author');
B<Note:> Be careful to put this code I<above> the C<1;> at the end of the
@@ -1179,31 +1206,20 @@
a statement that evaluates to C<true>. This is customarily done with
C<1;> on a line by itself.
-C<Important Note:> Although this tutorial uses plural names for both
-the names of the SQL tables and therefore the Result Classes (after
-all, C<Schema::Loader> automatically named the Result Classes from the
-names of the SQL tables it found), DBIx::Class users prefer singular
-names for these items. B<Please try to use singular table and DBIC
-model/Result Class names in your applications.> This tutorial will
-migrate to singular names as soon as possible (patches welcomed).
-B<Note that while singular is preferred for the DBIC model, plural is
-perfectly acceptable for the names of the controller classes.> After
-all, the C<Books.pm> controller operates on multiple books.
-
This code defines both a C<has_many> and a C<many_to_many>
relationship. The C<many_to_many> relationship is optional, but it
makes it easier to map a book to its collection of authors. Without
-it, we would have to "walk" though the C<book_authors> table as in
-C<$book-E<gt>book_authors-E<gt>first-E<gt>author-E<gt>last_name> (we
+it, we would have to "walk" though the C<book_author> table as in
+C<$book-E<gt>book_author-E<gt>first-E<gt>author-E<gt>last_name> (we
will see examples on how to use DBIx::Class objects in your code soon,
-but note that because C<$book-E<gt>book_authors> can return multiple
+but note that because C<$book-E<gt>book_author> can return multiple
authors, we have to use C<first> to display a single author).
-C<many_to_many> allows us to use the shorter C<$book-E<gt>authors-
+C<many_to_many> allows us to use the shorter C<$book-E<gt>author-
E<gt>first-E<gt>last_name>. Note that you cannot define a
C<many_to_many> relationship without also having the C<has_many>
relationship in place.
-Then edit C<lib/MyApp/Schema/Result/Authors.pm> and add relationship
+Then edit C<lib/MyApp/Schema/Result/Author.pm> and add relationship
information as follows (again, be careful to put in above the C<1;> but
below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
@@ -1216,7 +1232,7 @@
# 1) Name of relationship, DBIC will create an 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(book_author => 'MyApp::Schema::Result::BookAuthors', 'author_id');
+ __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'author_id');
# many_to_many():
# args:
@@ -1224,10 +1240,10 @@
# 2) Name of has_many() relationship this many_to_many() is shortcut for
# 3) Name of belongs_to() relationship in model class of has_many() above
# You must already have the has_many() defined to use a many_to_many().
- __PACKAGE__->many_to_many(books => 'book_author', 'book');
+ __PACKAGE__->many_to_many(book => 'book_author', 'book');
Finally, do the same for the "join table,"
-C<lib/MyApp/Schema/Result/BookAuthors.pm>:
+C<lib/MyApp/Schema/Result/BookAuthor.pm>:
#
# Set relationships:
@@ -1238,14 +1254,14 @@
# 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(book => 'MyApp::Schema::Result::Books', 'book_id');
+ __PACKAGE__->belongs_to(book => 'MyApp::Schema::Result::Book', 'book_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(author => 'MyApp::Schema::Result::Authors', 'author_id');
+ __PACKAGE__->belongs_to(author => 'MyApp::Schema::Result::Author', 'author_id');
=head2 Run The Application
@@ -1275,7 +1291,7 @@
Let's add a new column to our book list page that takes advantage of
the relationship information we manually added to our schema files in
the previous section. Edit C<root/src/books/list.tt2> and replace
-the "empty" tabase cell with the following:
+the "empty" table cell "<td></td>" with the following:
...
<td>
@@ -1310,16 +1326,16 @@
DBIx::Class):
SELECT me.id, me.title, me.rating FROM books me:
- 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 = ? ): '1'
- 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 = ? ): '2'
- 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 = ? ): '3'
- 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 = ? ): '4'
- 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 = ? ): '5'
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
+ JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '1'
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
+ JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '2'
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
+ JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '3'
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
+ JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '4'
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
+ JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '5'
Also note in C<root/src/books/list.tt2> that we are using "| html", a
type of TT filter, to escape characters such as E<lt> and E<gt> to <
@@ -1433,7 +1449,7 @@
# Retrieve all of the book records as book model objects and store in the
# stash where they can be accessed by the TT template
- $c->stash->{books} = [$c->model('DB::Books')->all];
+ $c->stash->{books} = [$c->model('DB::Book')->all];
# Set the TT template to use. You will almost always want to do this
# in your action methods (actions methods respond to user input in
@@ -1451,6 +1467,8 @@
the C<$c-E<gt>detach> mechanisms (these are discussed in Chapter 2 and
Chapter 9 of the Tutorial).
+B<IMPORTANT:> Make sure that you do NOT skip the following section
+before continuing to the next chapter 4 Basic CRUD.
=head2 Return To A Manually Specified Template
Modified: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod 2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod 2009-05-24 22:06:59 UTC (rev 10275)
@@ -59,7 +59,7 @@
You may have noticed that the Catalyst Helper scripts automatically
create basic C<.t> test scripts under the C<t> directory. This
chapter of the tutorial briefly looks at how these tests can be used
-to not only ensure that your application is working correctly at the
+not only to ensure that your application is working correctly at the
present time, but also provide automated regression testing as you
upgrade various pieces of your application over time.
@@ -67,7 +67,11 @@
Subversion repository as per the instructions in
L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
+For an excellent introduction to learning the many benefits of testing
+your Perl applications and modules, you might want to read 'Perl Testing:
+A Developer's Notebook' by Ian Langworth and chromatic.
+
=head1 RUNNING THE "CANNED" CATALYST TESTS
There are a variety of ways to run Catalyst and Perl tests (for example,
@@ -83,7 +87,7 @@
for errors:
# Failed test 'Request should succeed'
- # in t/controller_Books.t at line 8.
+ # at t/controller_Books.t line 8.
# Looks like you failed 1 test of 3.
The redirection used by the Authentication plugins will cause several
@@ -98,14 +102,26 @@
ok( request('/login')->is_success, 'Request should succeed' );
-2) Change the "C<request('/logout')-E<gt>is_success>" to
-"C<request('/logout')-E<gt>is_redirect>" in C<t/controller_Logout.t>.
+2) Change the line in C<t/controller_Logout.t> that reads:
-3) Change the "C<request('/books')-E<gt>is_success>" to
-"C<request('/books')-E<gt>is_redirect>" in C<t/controller_Books.t>.
+ ok( request('/logout')->is_success, 'Request should succeed' );
-4) Add "C<use MyApp;>" to the top of C<t/view_TT.t>.
+to:
+ ok( request('/logout')->is_redirect, 'Request should succeed' );
+
+3) Change the line in C<t/controller_Books.t> that reads:
+
+ ok( request('/books')->is_success, 'Request should succeed' );
+
+to:
+
+ ok( request('/books')->is_redirect, 'Request should succeed' );
+
+4) Add the following statement to the top of C<t/view_TT.t>:
+
+ use MyApp;
+
As you can see in the C<prove> command line above, the C<--lib> option
is used to set the location of the Catalyst C<lib> directory. With this
command, you will get all of the usual development server debug output,
@@ -118,7 +134,7 @@
B<Note:> Depending on the versions of various modules you have
installed, you might get some C<used only once> warnings -- you can
-ignore these. If you want to elliminate the warnings, you can
+ignore these. If you want to eliminate the warnings, you can
edit C<Template::Base> to disable and then re-enable warnings
are the C</usr/lib/perl5/Template/Base.pm> line in C<sub new>.
You can locate where C<Template::Base> is located with the
@@ -221,12 +237,7 @@
# Log in as each user
# Specify username and password on the URL
$ua1->get_ok("http://localhost/login?username=test01&password=mypass", "Login 'test01'");
- # Use the form for user 'test02'; note there is no description here
- $ua2->submit_form(
- fields => {
- username => 'test02',
- password => 'mypass',
- });
+ $ua1->get_ok("http://localhost/login?username=test02&password=mypass", "Login 'test02'");
# Go back to the login page and it should show that we are already logged in
$_->get_ok("http://localhost/login", "Return to '/login'") for $ua1, $ua2;
More information about the Catalyst-commits
mailing list