[Catalyst-commits] r12902 - Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial

hkclark at dev.catalyst.perl.org hkclark at dev.catalyst.perl.org
Tue Feb 16 18:09:35 GMT 2010


Author: hkclark
Date: 2010-02-16 18:09:35 +0000 (Tue, 16 Feb 2010)
New Revision: 12902

Modified:
   Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod
Log:
Add some additional background info & links about auto-defined DBIC relationships
Amend directions to be sure they have new enough C::M::DBIC::Schema & DBD::SQLite
Add background info on on_connect_do
Adjust use of "-r" on dev server and provide some background info
Other misc adjustments

Modified: Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod
===================================================================
--- Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod	2010-02-16 11:07:36 UTC (rev 12901)
+++ Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod	2010-02-16 18:09:35 UTC (rev 12902)
@@ -102,13 +102,15 @@
 
 =head1 EDIT THE LIST OF CATALYST PLUGINS
 
-One of the greatest benefits of Catalyst is that it has such a large
-library of plugins and base classes available.  Plugins are used to
-seamlessly integrate existing Perl modules into the overall Catalyst
-framework.  In general, they do this by adding additional methods to the
-C<context> object (generally written as C<$c>) that Catalyst passes to
-every component throughout the framework.
+One of the greatest benefits of Catalyst is that it has such a large 
+library of bases classes and plugins available that you can use easily 
+add functionality to your application. Plugins are used to seamlessly 
+integrate existing Perl modules into the overall Catalyst framework. In 
+general, they do this by adding additional methods to the C<context> 
+object (generally written as C<$c>) that Catalyst passes to every 
+component throughout the framework. 
 
+
 By default, Catalyst enables three plugins/flags:
 
 =over 4
@@ -226,7 +228,7 @@
 Don't let these variations confuse you -- they all accomplish the same 
 result.
 
-This tells Catalyst to start using one new plugin, 
+This tells Catalyst to start using one additional plugin, 
 L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>, to add a 
 stack trace to the standard Catalyst "debug screen" (the screen 
 Catalyst sends to your browser when an error occurs). Be aware that 
@@ -293,7 +295,7 @@
     
     =cut
     
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
@@ -323,7 +325,7 @@
 Catalyst and plugin functionality.
 
 Catalyst actions are regular Perl methods, but they make use of 
-attributes (the "C<: Local>" next to the "C<sub list>" in the code 
+attributes (the "C<:Local>" next to the "C<sub list>" in the code 
 above) to provide additional information to the Catalyst dispatcher 
 logic (note that the space between the colon and the attribute name is 
 optional; you will see attributes written both ways).  Most Catalyst 
@@ -543,7 +545,7 @@
 
 To test your work so far, first start the development server:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
 
 Then point your browser to L<http://localhost:3000> and you should
 still get the Catalyst welcome page.  Next, change the URL in your
@@ -567,10 +569,10 @@
 lightweight and easy to use. Be sure to get at least version 3. Open
 C<myapp01.sql> in your editor and enter:
 
-    PRAGMA foreign_keys = ON;
     --
     -- Create a very simple database to hold book and author information
     --
+    PRAGMA foreign_keys = ON;
     CREATE TABLE book (
             id          INTEGER PRIMARY KEY,
             title       TEXT ,
@@ -625,8 +627,9 @@
 database contents:
 
     $ sqlite3 myapp.db
-    SQLite version 3.5.9
+    SQLite version 3.6.22
     Enter ".help" for instructions
+    Enter SQL statements terminated with a ";"
     sqlite> select * from book;
     1|CCSP SNRS Exam Certification Guide|5
     2|TCP/IP Illustrated, Volume 1|5
@@ -689,29 +692,36 @@
 =head2 Make Sure You Have a Recent Version of the DBIx::Class Model
 
 First, let's be sure we have a recent version of the DBIC helper,
-L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>, by
-running this command:
+L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>, so
+that we can take advantage of some recent enhancements in how
+foreign keys are handled with SQLite.  To check your version, 
+run this command:
 
     $ perl -MCatalyst::Model::DBIC::Schema -e \
         'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
-    0.31
+    0.39
 
 Please note the '\' above.  Depending on your environment, you might 
 be able to cut and paste the text as shown or need to remove the '\' 
 character to that the command is all on a single line.
 
-You should have version 0.31 or greater if you are following along 
-with Debian 5.  In other environments, you may need to run this 
-command to install it directly from CPAN:
+If you have less than v0.39, you will need to run this command to 
+install it directly from CPAN:
 
     $ sudo cpan Catalyst::Model::DBIC::Schema
 
 And re-run the version print command to verify that you are now at 
-0.31 or higher.
+0.39 or higher.
 
-Please use version C<1.27> of L<DBD::SQLite> or later for proper foreign key
-support.
+In addition, since we are using SQLite's foreign key support here,
+please be sure that you use version C<1.27> of L<DBD::SQLite> or later:
 
+    $ perl -MDBD::SQLite -e 'print "$DBD::SQLite::VERSION\n"'
+    1.29
+
+Upgrade if you are not at version C<1.27> or higher.
+
+
 =head2 Create Static DBIx::Class Schema Files
 
 Before you continue, make sure your C<myapp.db> database file is in 
@@ -761,9 +771,21 @@
 
 =item *
 
-And finally, C<dbi:SQLite:myapp.db> is the standard DBI connect string 
+C<dbi:SQLite:myapp.db> is the standard DBI connect string 
 for use with SQLite.
 
+=item *
+
+And finally, the C<on_connect_do> string requests that 
+L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> create 
+foreign key relationships for us (this is not needed for databases such 
+as PostgreSQL and MySQL, but is required for SQLite). If you take a look 
+at C<lib/MyApp/Model/DB.pm>, you will see that the SQLite pragma is 
+propogated to the Model, so that SQLite's recent (and optional) foreign 
+key enforcement is enabled at the start of every database connection. 
+
+
+
 =back
 
 If you look in the C<lib/MyApp/Schema.pm> file, you will find that it 
@@ -813,6 +835,7 @@
         dbi:SQLite:myapp.db \
         on_connect_do="PRAGMA foreign_keys = ON"
 
+
 =head1 ENABLE THE MODEL IN THE CONTROLLER
 
 Open C<lib/MyApp/Controller/Books.pm> and un-comment the model code we 
@@ -826,14 +849,14 @@
     
     =cut
     
-    sub list : Local {
+    sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
         my ($self, $c) = @_;
     
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template
+        # 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::Book')->all];
     
         # Set the TT template to use.  You will almost always want to do this
@@ -869,10 +892,12 @@
 First, let's enable an environment variable that causes DBIx::Class to 
 dump the SQL statements used to access the database.  This is a 
 helpful trick when you are trying to debug your database-oriented 
-code:
+code.  Press C<Ctrl-C> to break out of the development server and
+enter:
 
     $ export DBIC_TRACE=1
-
+    $ script/myapp_server.pl -r 
+    
 This assumes you are using bash as your shell -- adjust accordingly if
 you are using a different shell (for example, under tcsh, use
 C<setenv DBIC_TRACE 1>).
@@ -886,14 +911,13 @@
 Then launch the Catalyst development server.  The log output should
 display something like:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
     [debug] Debug messages enabled
     [debug] Statistics enabled
     [debug] Loaded plugins:
     .----------------------------------------------------------------------------.
     | Catalyst::Plugin::ConfigLoader  0.27                                       |
     | Catalyst::Plugin::StackTrace  0.11                                         |
-    | Catalyst::Plugin::Static::Simple  0.25                                     |
     '----------------------------------------------------------------------------'
     
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
@@ -934,7 +958,7 @@
     | /books/list                         | /books/list                          |
     '-------------------------------------+--------------------------------------'
     
-    [info] MyApp powered by Catalyst 5.80013
+    [info] MyApp powered by Catalyst 5.80020
     You can connect to your server at http://debian:3000
 
 B<NOTE:> Be sure you run the C<script/myapp_server.pl> command from
@@ -1147,23 +1171,128 @@
 
 =head2 Test Run The Application
 
-Restart the development server and hit "Reload" in your web browser
-and you should now see a formatted version of our basic book list.
-Although our wrapper and stylesheet are obviously very simple, you
-should see how it allows us to control the overall look of an entire
-website from two central files.  To add new pages to the site, just
-provide a template that fills in the C<content> section of our wrapper
-template -- the wrapper will provide the overall feel of the page.
+Hit "Reload" in your web browser and you should now see a formatted 
+version of our basic book list. (Again, the development server should 
+have automatically restarted when you made changes to 
+C<lib/MyApp/View/TT.pm>. If you are not using the "-r" option, you will 
+need to hit C<Ctrl-C> and manually restart it. Also note that the 
+development server does I<NOT> need to restart for changes to the TT and 
+static files we created and edited in the C<root> directory -- those 
+updates are handled on a per-request basis.) 
 
+Although our wrapper and stylesheet are obviously very simple, you 
+should see how it allows us to control the overall look of an entire 
+website from two central files. To add new pages to the site, just 
+provide a template that fills in the C<content> section of our wrapper 
+template -- the wrapper will provide the overall feel of the page. 
 
+
 =head2 Updating the Generated DBIx::Class Result Class Files
 
-Let's manually add some relationship information to the auto-generated 
-Result Class files. C<many_to_many> relationships are not currently
-automatically generated by L<DBIx::Class::Schema::Loader>.
-First edit C<lib/MyApp/Schema/Result/Book.pm> and add the 
-following text below the C<# You can replace this text...> comment:
+If you take a look at the Schema files automatically generated by 
+L<DBIx::Class::Schema::Loader>, you will see that it has already defined 
+C<has_many> and C<belongs_to> relationships on each side of our foreign 
+keys. For example, take a look at C<lib/MyApp/Schema/Result/Book.pm> and 
+notice the following code: 
 
+    =head1 RELATIONS
+
+    =head2 book_authors
+
+    Type: has_many
+
+    Related object: L<MyApp::Schema::Result::BookAuthor>
+
+    =cut
+
+    __PACKAGE__->has_many(
+      "book_authors",
+      "MyApp::Schema::Result::BookAuthor",
+      { "foreign.book_id" => "self.id" },
+    );
+
+Each C<Book> "has_many" C<book_authors>, where C<BookAuthor> is
+the many-to-many table that allows each Book to have multiple
+Authors, and each Author to have mulitple books.  The arguments
+to C<has_many> are:
+
+=over 4
+
+=item *
+
+C<book_authors> - The name for this relationship.  DBIC will create
+an accessor on the C<Books> DBIC Row object with this name.
+
+=item *
+
+C<MyApp::Schema::Result::BookAuthor> - The name of the DBIC model
+class referenced by this C<has_many> relationship.
+
+=item *
+
+C<foreign.book_id> - C<book_id> is the name of the foreign key 
+column in the I<foreign> table that points back to this table.
+
+=item *
+
+C<self.id> - C<id> is the name of the column in I<this> table
+that is referenced by the foreign key.
+
+=back
+
+See L<DBIx::Class::Relationship/has_many> for
+additional information.  Note that you might see a "hand coded"
+version of the C<has_many> relationship above expressed as:
+
+    __PACKAGE__->has_many(
+      "book_authors",
+      "MyApp::Schema::Result::BookAuthor",
+      "book_id",
+    );
+
+Where the third argument is simply the name of the column in
+the foreign table.  However, the hashref syntax used by 
+L<DBIx::Class::Schema::Loader> is more flexible (for example,
+it can handle "multi-column" foreign keys).
+
+B<Note:> If you are using older versions of SQLite and related DBIC 
+tools, you will need to manually define your C<has_many> and 
+C<belongs_to> relationships. We recommend upgrading to the versions 
+specified above. :-) 
+
+Have a look at C<lib/MyApp/Schema/Result/BookAuthor.pm> and notice
+that there is a C<belongs_to> relationship defined that acts as the
+"mirror image" to the C<has_many> relationship we just looked at
+above:
+
+    =head1 RELATIONS
+
+    =head2 book
+
+    Type: belongs_to
+
+    Related object: L<MyApp::Schema::Result::Book>
+
+    =cut
+
+    __PACKAGE__->belongs_to(
+      "book",
+      "MyApp::Schema::Result::Book",
+      { id => "book_id" },
+      { join_type => "LEFT" },
+    );
+
+
+The arguments are similar, but see 
+L<DBIx::Class::Relationship/belongs_to> for the details.
+    
+Although recent versions of SQLite and L<DBIx::Class::Schema::Loader> 
+automatically handle the C<has_many> and C<belongs_to> relationships, 
+C<many_to_many> relationships currently need to be manually inserted. 
+To add a C<many_to_many> relationship, first edit 
+C<lib/MyApp/Schema/Result/Book.pm> and add the following text below 
+the C<# You can replace this text...> comment:
+
     # many_to_many():
     #   args:
     #     1) Name of relationship, DBIC will create accessor with this name
@@ -1177,8 +1306,7 @@
 a statement that evaluates to C<true>.  This is customarily done with
 C<1;> on a line by itself.
 
-You'll notice there is already a C<has_many> relationship called
-C<book_authors>. The C<many_to_many> relationship is optional, but it makes it
+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_author> table as in 
 C<$book-E<gt>book_author-E<gt>first-E<gt>author-E<gt>last_name> (we 
@@ -1190,9 +1318,10 @@
 define a C<many_to_many> relationship without also having the 
 C<has_many> relationship in place.
 
-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):
+Then edit C<lib/MyApp/Schema/Result/Author.pm> and add the reverse 
+C<many_to_many> relationship for C<Author> as follows (again, be careful 
+to put in above the C<1;> but below the C<# DO NOT MODIFY THIS OR 
+ANYTHING ABOVE!> comment): 
 
     # many_to_many():
     #   args:
@@ -1202,13 +1331,14 @@
     #   You must already have the has_many() defined to use a many_to_many().
     __PACKAGE__->many_to_many(books => 'book_authors', 'book');
 
+
 =head2 Run The Application
 
 Run the Catalyst development server script with the C<DBIC_TRACE> option
 (it might still be enabled from earlier in the tutorial, but here is an
 alternate way to specify the option just in case):
 
-    $ DBIC_TRACE=1 script/myapp_server.pl
+    $ DBIC_TRACE=1 script/myapp_server.pl -r
 
 Make sure that the application loads correctly and that you see the
 three dynamically created model class (one for each of the




More information about the Catalyst-commits mailing list