remove trailing whitespace
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / 09_AdvancedCRUD / 09_FormFu.pod
index 113720f..0dcc0af 100644 (file)
@@ -56,34 +56,45 @@ L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
 
 =head1 DESCRIPTION
 
-This portion of the tutorial explores L<HTML::FormFu|HTML::FormFu> and 
-how it can be used to manage forms, perform validation of form input, 
-as well as save and restore data to/from the database.  This was written
-using HTML::FormFu version 0.05001.
+This portion of the tutorial explores L<HTML::FormFu> and how it can be
+used to manage forms, perform validation of form input, as well as save
+and restore data to/from the database.
 
-See 
-L<Catalyst::Manual::Tutorial::09_AdvancedCRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
-for additional form management options other than 
-L<HTML::FormFu|HTML::FormFu>.
+See L<Catalyst::Manual::Tutorial::09_AdvancedCRUD> for additional form
+management options other than L<HTML::FormFu>.
+
+Source code for the tutorial in included in the F</home/catalyst/Final>
+directory of the Tutorial Virtual machine (one subdirectory per
+chapter).  There are also instructions for downloading the code in
+L<Catalyst::Manual::Tutorial::01_Intro>.
 
 
 =head1 HTML::FormFu FORM CREATION
 
-This section looks at how L<HTML::FormFu|HTML::FormFu> can be used to 
-add additional functionality to the manually created form from Chapter 4.
+This section looks at how L<HTML::FormFu> can be used to add additional
+functionality to the manually created form from
+L<Chapter 4|Catalyst::Manual::Tutorial::04_BasicCRUD>.
 
 
 =head2 Inherit From Catalyst::Controller::HTML::FormFu
 
 First, change your C<lib/MyApp/Controller/Books.pm> to inherit from
-L<Catalyst::Controller::HTML::FormFu|Catalyst::Controller::HTML::FormFu>
-by changing the C<use parent> line from the default of:
+L<Catalyst::Controller::HTML::FormFu> by changing the C<extends> line
+from the default of:
 
-    use parent 'Catalyst::Controller';
+    BEGIN {extends 'Catalyst::Controller'; }
 
 to use the FormFu base controller class:
 
-    use parent 'Catalyst::Controller::HTML::FormFu';
+    BEGIN {extends 'Catalyst::Controller::HTML::FormFu'; }
+
+Don't forget to add:
+
+    requires 'HTML::FormFu';
+    requires 'Catalyst::Controller::HTML::FormFu';
+    requires 'HTML::FormFu::Model::DBIC';
+
+to your C<Makefile.PL>.
 
 
 =head2 Add Action to Display and Save the Form
@@ -92,17 +103,17 @@ Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
 following method:
 
     =head2 formfu_create
-    
+
     Use HTML::FormFu to create a new book
-    
+
     =cut
-    
+
     sub formfu_create :Chained('base') :PathPart('formfu_create') :Args(0) :FormConfig {
         my ($self, $c) = @_;
-    
+
         # Get the form that the :FormConfig attribute saved in the stash
         my $form = $c->stash->{form};
-  
+
         # Check if the form has been submitted (vs. displaying the initial
         # form) and if the data passed validation.  "submitted_and_valid"
         # is shorthand for "$form->submitted && !$form->has_errors"
@@ -111,10 +122,9 @@ following method:
             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
-            $c->flash->{status_msg} = 'Book created';
-            # Return to the books list
-            $c->response->redirect($c->uri_for($self->action_for('list'))); 
+            # Set a status message for the user & return to books list
+            $c->response->redirect($c->uri_for($self->action_for('list'),
+                {mid => $c->set_status_msg("Book created")}));
             $c->detach;
         } else {
             # Get the authors from the DB
@@ -129,21 +139,21 @@ following method:
             # Add the authors to it
             $select->options(\@authors);
         }
-        
+
         # Set the template
-        $c->stash->{template} = 'books/formfu_create.tt2';
+        $c->stash(template => 'books/formfu_create.tt2');
     }
 
 
 =head2 Create a Form Config File
 
 Although C<HTML::FormFu> supports any configuration file handled by
-L<Config::Any|Config::Any>, most people tend to use YAML.  First
-create a directory to hold your form configuration files:
+L<Config::Any>, most people tend to use YAML.  First create a directory
+to hold your form configuration files:
 
-    mkdir -p root/forms/books
+    $ mkdir -p root/forms/books
 
-Then create the file C<root/forms/books/formfu_create.yml> and enter the 
+Then create the file C<root/forms/books/formfu_create.yml> and enter the
 following text:
 
     ---
@@ -158,14 +168,14 @@ following text:
           # This is an optional 'mouse over' title pop-up
           attributes:
             title: Enter a book title here
-    
+
         # Another text field for the numeric rating
         - type: Text
           name: rating
           label: Rating
           attributes:
             title: Enter a rating between 1 and 5 here
-    
+
         # Add a drop-down list for the author selection.  Note that we will
         # dynamically fill in all the authors from the controller but we
         # could manually set items in the drop-list by adding this YAML code:
@@ -175,21 +185,21 @@ following text:
         - type: Select
           name: authors
           label: Author
-    
+
         # The submit button
         - type: Submit
           name: submit
           value: Submit
 
-B<NOTE:> Copying and pasting YAML from perl documentation is sometimes
+B<NOTE:> Copying and pasting YAML from Perl documentation is sometimes
 tricky.  See the L<Config::General Config for this tutorial> section of
 this document for a more foolproof config format.
 
 
 =head2 Update the CSS
 
-Edit C<root/static/css/main.css> and add the following lines to the bottom of
-the file:
+Edit C<root/static/css/main.css> and add the following lines to the
+bottom of the file:
 
     ...
     input {
@@ -203,23 +213,21 @@ the file:
         display: block;
     }
 
-These changes will display form elements vertically.  Note that the 
-existing definition of the C<.error> class is pulling the color scheme 
-settings from the C<root/lib/config/col> file that was created by the 
-TTSite helper.  This allows control over the CSS color settings from a 
-single location.
+These changes will display form elements vertically.
 
 
 =head2 Create a Template Page To Display The Form
 
-Open C<root/src/books/formfu_create.tt2> in your editor and enter the following:
+Open C<root/src/books/formfu_create.tt2> in your editor and enter the
+following:
 
     [% META title = 'Create/Update Book' %]
-    
+
     [%# Render the HTML::FormFu Form %]
     [% form %]
-    
-    <p><a href="[% c.uri_for(c.controller.action_for('list')) %]">Return to book list</a></p>
+
+    <p><a href="[% c.uri_for(c.controller.action_for('list'))
+        %]">Return to book list</a></p>
 
 
 =head2 Add Links for Create and Update via C<HTML::FormFu>
@@ -233,35 +241,34 @@ the bottom of the existing file:
       <a href="[% c.uri_for(c.controller.action_for('formfu_create')) %]">Create</a>
     </p>
 
-This adds a new link to the bottom of the book list page that we can
-use to easily launch our HTML::FormFu-based form.
+This adds a new link to the bottom of the book list page that we can use
+to easily launch our HTML::FormFu-based form.
 
 
 =head2 Test The HTML::FormFu Create Form
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
+Make sure the server is running with the "-r" restart option:
 
-    $ script/myapp_server.pl
+    $ script/myapp_server.pl -r
 
 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
-Author: Comer
-    
-Click the Submit button, and you will be returned to the Book List page
+    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 the value of the rating 
-(you can use any number you want, and even non-numeric values with 
+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 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.
 
 B<Note:> Depending on the database you are using and how you established
@@ -273,19 +280,18 @@ performing any validation.
 
 =head1 HTML::FormFu VALIDATION AND FILTERING
 
-Although the use of L<HTML::FormFu|HTML::FormFu> in the previous section 
-did provide an automated mechanism to build the form, the real power of 
-this module stems from functionality that can automatically validate and 
-filter the user input.  Validation uses constraints to be sure that 
-users input appropriate data (for example, that the email field of a 
-form contains a valid email address).  Filtering can also be used to 
-remove extraneous whitespace from fields or to escape meta-characters in 
-user input.
+Although the use of L<HTML::FormFu> in the previous section did provide
+an automated mechanism to build the form, the real power of this module
+stems from functionality that can automatically validate and filter the
+user input.  Validation uses constraints to be sure that users input
+appropriate data (for example, that the email field of a form contains a
+valid email address).  Filtering can also be used to remove extraneous
+whitespace from fields or to escape meta-characters in user input.
 
 
 =head2 Add Constraints
 
-Open C<root/forms/books/formfu_create.yml> in your editor and update it 
+Open C<root/forms/books/formfu_create.yml> in your editor and update it
 to match:
 
     ---
@@ -308,7 +314,7 @@ to match:
               max: 40
               # Override the default of 'Invalid input'
               message: Length must be between 5 and 40 characters
-    
+
         # Another text field for the numeric rating
         - type: Text
           name: rating
@@ -332,7 +338,7 @@ to match:
               min: 1
               max: 5
               message: "Must be between 1 and 5."
-    
+
         # Add a select list for the author selection.  Note that we will
         # dynamically fill in all the authors from the controller but we
         # could manually set items in the select by adding this YAML code:
@@ -353,25 +359,25 @@ to match:
           constraints:
             # Make sure it's a number
             - Integer
-    
+
         # The submit button
         - type: Submit
           name: submit
           value: Submit
-    
+
     # Global filters and constraints.
     constraints:
-      # The user cannot leave any fields blank
-      - Required
-      # If not all fields are required, move the Required constraint to the 
-      # fields that are
+        # The user cannot leave any fields blank
+        - Required
+        # If not all fields are required, move the Required constraint to the
+        # fields that are
     filter:
-      # Remove whitespace at both ends
-      - TrimEdges
-      # Escape HTML characters for safety
-      - HTMLEscape
+        # Remove whitespace at both ends
+        - TrimEdges
+        # Escape HTML characters for safety
+        - HTMLEscape
 
-B<NOTE:> Copying and pasting YAML from perl documentation is sometimes
+B<NOTE:> Copying and pasting YAML from Perl documentation is sometimes
 tricky.  See the L<Config::General Config for this tutorial> section of
 this document for a more foolproof config format.
 
@@ -382,69 +388,67 @@ The main changes are:
 =item *
 
 The C<Select> element for C<authors> is changed from a single-select
-drop-down to a multi-select list by adding configuration for the 
+drop-down to a multi-select list by adding configuration for the
 C<multiple> and C<size> options in C<formfu_create.yml>.
 
 =item *
 
 Constraints are added to provide validation of the user input.  See
-L<HTML::FormFu::Constraint|HTML::FormFu::Constraint> for other
-constraints that are available.
+L<HTML::FormFu::Constraint> for other constraints that are available.
 
 =item *
 
-A variety of filters are run on every field to remove and escape 
-unwanted input.  See L<HTML::FormFu::Filter|HTML::FormFu::Filter>
-for more filter options.
+A variety of filters are run on every field to remove and escape
+unwanted input.  See L<HTML::FormFu::Filter> for more filter options.
 
 =back
 
 
 =head2 Try Out the Updated Form
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still 
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-Make sure you are still logged in as C<test01> and try adding a book 
-with various errors: title less than 5 characters, non-numeric rating, a 
-rating of 0 or 6, etc.  Also try selecting one, two, and zero authors. 
-When you click Submit, the HTML::FormFu C<constraint> items will 
-validate the logic and insert feedback as appropriate.  Try adding blank 
-spaces at the front or the back of the title and note that it will be 
+Make sure you are still logged in as C<test01> and try adding a book
+with various errors: title less than 5 characters, non-numeric rating, a
+rating of 0 or 6, etc.  Also try selecting one, two, and zero authors.
+When you click Submit, the HTML::FormFu C<constraint> items will
+validate the logic and insert feedback as appropriate.  Try adding blank
+spaces at the front or the back of the title and note that it will be
 removed.
 
+Note that you can update your FormFu YAML forms and the development
+server does not need to reload -- the form definition is read from
+the YAML file each time a controller action uses it.
+
 
 =head1 CREATE AND UPDATE/EDIT ACTION
 
-Let's expand the work done above to add an edit action.  First, open 
-C<lib/MyApp/Controller/Books.pm> and add the following method to the 
+Let's expand the work done above to add an edit action.  First, open
+C<lib/MyApp/Controller/Books.pm> and add the following method to the
 bottom:
 
     =head2 formfu_edit
-    
+
     Use HTML::FormFu to update an existing book
-    
+
     =cut
-    
-    sub formfu_edit :Chained('object') :PathPart('formfu_edit') :Args(0) 
+
+    sub formfu_edit :Chained('object') :PathPart('formfu_edit') :Args(0)
             :FormConfig('books/formfu_create.yml') {
         my ($self, $c) = @_;
-    
+
         # Get the specified book already saved by the 'object' method
         my $book = $c->stash->{object};
-    
+
         # Make sure we were able to get a book
         unless ($book) {
-            $c->flash->{error_msg} = "Invalid book -- Cannot edit";
-            $c->response->redirect($c->uri_for($self->action_for('list')));
+            # Set an error message for the user & return to books list
+            $c->response->redirect($c->uri_for($self->action_for('list'),
+                {mid => $c->set_error_msg("Invalid book -- Cannot edit")}));
             $c->detach;
         }
-    
+
         # Get the form that the :FormConfig attribute saved in the stash
         my $form = $c->stash->{form};
-    
+
         # Check if the form has been submitted (vs. displaying the initial
         # form) and if the data passed validation.  "submitted_and_valid"
         # is shorthand for "$form->submitted && !$form->has_errors"
@@ -452,9 +456,9 @@ bottom:
             # Save the form data for the book
             $form->model->update($book);
             # Set a status message for the user
-            $c->flash->{status_msg} = 'Book edited';
-            # Return to the books list
-            $c->response->redirect($c->uri_for($self->action_for('list')));
+            # Set a status message for the user & return to books list
+            $c->response->redirect($c->uri_for($self->action_for('list'),
+                {mid => $c->set_status_msg("Book edited")}));
             $c->detach;
         } else {
             # Get the authors from the DB
@@ -471,27 +475,27 @@ bottom:
             # Populate the form with existing values from DB
             $form->model->default_values($book);
         }
-    
+
         # Set the template
-        $c->stash->{template} = 'books/formfu_create.tt2';
+        $c->stash(template => 'books/formfu_create.tt2');
     }
 
-Most of this code should look familiar to what we used in the 
-C<formfu_create> method (in fact, we should probably centralize some of 
+Most of this code should look familiar to what we used in the
+C<formfu_create> method (in fact, we should probably centralize some of
 the common code in separate methods).  The main differences are:
 
 =over 4
 
 =item *
 
-We have to manually specify the name of the FormFu .yml file as an 
-argument to C<:FormConfig> because the name can no longer be 
+We have to manually specify the name of the FormFu .yml file as an
+argument to C<:FormConfig> because the name can no longer be
 automatically deduced from the name of our action/method (by default,
 FormFu would look for a file named C<books/formfu_edit.yml>).
 
 =item *
 
-We load the book object from the stash (found using the $id passed to 
+We load the book object from the stash (found using the $id passed to
 the Chained object method)
 
 =item *
@@ -500,56 +504,53 @@ We use C<$id> to look up the existing book from the database.
 
 =item *
 
-We make sure the book lookup returned a valid book.  If not, we set 
-the error message and return to the book list.
+We make sure the book lookup returned a valid book.  If not, we set the
+error message and return to the book list.
 
 =item *
 
-If the form has been submitted and passes validation, we skip creating a 
-new book and just use C<$form-E<gt>model-E<gt>update> to update the existing 
-book.
+If the form has been submitted and passes validation, we skip creating a
+new book and just use C<$form-E<gt>model-E<gt>update> to update the
+existing book.
 
 =item *
 
-If the form is being displayed for the first time (or has failed 
+If the form is being displayed for the first time (or has failed
 validation and it being redisplayed), we use
- C<$form-E<gt>model-E<gt>default_values> to populate the form with data from the
-database.
+C<$form-E<gt>model-E<gt>default_values> to populate the form with data
+from the database.
 
 =back
 
-Then, edit C<root/src/books/list.tt2> and add a new link below the 
-existing "Delete" link that allows us to edit/update each existing book. 
-The last E<lt>tdE<gt> cell in the book list table should look like the 
+Then, edit C<root/src/books/list.tt2> and add a new link below the
+existing "Delete" link that allows us to edit/update each existing book.
+The last E<lt>tdE<gt> cell in the book list table should look like the
 following:
 
     ...
     <td>
       [% # Add a link to delete a book %]
-      <a href="[% c.uri_for(c.controller.action_for('delete'), [book.id]) %]">Delete</a>
+      <a href="[%
+        c.uri_for(c.controller.action_for('delete'), [book.id]) %]">Delete</a>
       [% # Add a link to edit a book %]
-      <a href="[% c.uri_for(c.controller.action_for('formfu_edit'), [book.id]) %]">Edit</a>
+      <a href="[%
+        c.uri_for(c.controller.action_for('formfu_edit'), [book.id]) %]">Edit</a>
     </td>
     ...
 
-B<Note:> Only add two lines (the "Add a link to edit a book" comment
-and the href for C<formfu_edit>).  Make sure you add it below the
-existing C<delete> link.
+B<Note:> Only add three lines (the "Add a link to edit a book" comment and
+the href for C<formfu_edit>).  Make sure you add it below the existing
+C<delete> link.
 
 
 =head2 Try Out the Edit/Update Feature
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still 
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-Make sure you are still logged in as C<test01> and go to the 
-L<http://localhost:3000/books/list> URL in your browser.  Click the 
-"Edit" link next to "Internetworking with TCP/IP Vol. II", change the 
-rating to a 3, the "II" at end of the title to the number "2", add 
-Stevens as a co-author (control-click), and click Submit.  You will then 
-be returned to the book list with a "Book edited" message at the top in 
+Make sure you are still logged in as C<test01> and go to the
+L<http://localhost:3000/books/list> URL in your browser.  Click the
+"Edit" link next to "Internetworking with TCP/IP Vol. II", change the
+rating to a 3, the "II" at end of the title to the number "2", add
+Stevens as a co-author (control-click), and click Submit.  You will then
+be returned to the book list with a "Book edited" message at the top in
 green.  Experiment with other edits to various books.
 
 
@@ -585,13 +586,12 @@ Or you can proceed to write your own application, which is probably the
 real reason you worked through this Tutorial in the first place.
 
 
-=head2  Config::General Config for this tutorial
+=head2 Config::General Config for this tutorial
 
 If you are having difficulty with YAML config above, please save the
 below into the file C<formfu_create.conf> and delete the
-C<formfu_create.yml> file.  The below is in
-L<Config::General|Config::General> format which follows the syntax of
-Apache config files.
+C<formfu_create.yml> file.  The below is in L<Config::General> format
+which follows the syntax of Apache config files.
 
    constraints   Required
    <elements>
@@ -637,15 +637,16 @@ Apache config files.
        type   Submit
    </elements>
    indicator   submit
-   
+
 
 =head1 AUTHOR
 
 Kennedy Clark, C<hkclark@gmail.com>
 
-Please report any errors, issues or suggestions to the author.  The
-most recent version of the Catalyst Tutorial can be found at
-L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/>.
+Feel free to contact the author for any errors or suggestions, but the
+best way to report issues is via the CPAN RT Bug system at
+L<https://rt.cpan.org/Public/Dist/Display.html?Name=Catalyst-Manual>.
 
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).    
+Copyright 2006-2011, Kennedy Clark, under the
+Creative Commons Attribution Share-Alike License Version 3.0
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).