X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FTutorial%2FAdvancedCRUD.pod;h=4fa2d31dc3b5c2e252987ae4dead629c6ec16238;hb=785c4199551c6e95f12f13420276c4aa9f3611c2;hp=22f562b3ff0a42773d3cba903141ad4550a555a9;hpb=64ccd8a8bfbc16276c044c94702b1440c2897695;p=catagits%2FCatalyst-Runtime.git diff --git a/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod b/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod index 22f562b..4fa2d31 100644 --- a/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod +++ b/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod @@ -2,8 +2,6 @@ Catalyst::Manual::Tutorial::AdvancedCRUD - Catalyst Tutorial - Part 8: Advanced CRUD - - =head1 OVERVIEW This is B for the Catalyst tutorial. @@ -46,12 +44,10 @@ B =item 9 -L +L =back - - =head1 DESCRIPTION This part of the tutorial explores more advanced functionality for @@ -62,50 +58,46 @@ validation of user-entered data, and automated transfer of data between forms and model objects. In keeping with the Catalyst (and Perl) spirit of flexibility, there are -many different ways approach advanced CRUD operations in a Catalyst +many different ways to approach advanced CRUD operations in a Catalyst environment. One alternative is to use -L -to instantly construct a set of Controller methods and templates for -basic CRUD operations. Although a popular subject in Quicktime movies -that serve as promotional material for various frameworks, more -real-world applications require more control. Other options include -L and +L +to instantly construct a set of Controller methods and templates for +basic CRUD operations. Although a popular subject in Quicktime +movies that serve as promotional material for various frameworks, +real-world applications generally require more control. Other +options include L and L. -Here, we will make use of the L to not only -ease form creation, but to also provide validation of the submitted -data. The approached used by the part of the tutorial is to slowly -incorporate additional L functionality in a -step-wise fashion (we start with fairly simple form creation and then -move on to more complex and "magical" features such as validation and +Here, we will make use of the L to not only +ease form creation, but to also provide validation of the submitted +data. The approached used by the part of the tutorial is to slowly +incorporate additional L functionality in a +step-wise fashion (we start with fairly simple form creation and then +move on to more complex and "magical" features such as validation and auto-population/auto-saving). -B Part 8 of the tutorial is optional. Users who do not which to -use L may skip this section. +B Part 8 of the tutorial is optional. Users who do not wish to +use L may skip this part. B: Note that all of the code for this part of the tutorial can be pulled from the Catalyst Subversion repository in one step with the following command: - svn checkout http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial@### + svn checkout http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial@4627 . IMPORTANT: Does not work yet. Will be completed for final version. - - =head1 C FORM CREATION This section looks at how L can be used to add additional functionality to the manually created form from Part 3. - =head2 Add the C Plugin Open C in your editor and add the following to the list of -plugins (be sure to leave the existing plugins enabled: +plugins (be sure to leave the existing plugins enabled): HTML::Widget - =head2 Add a Form Creation Helper Method Open C in your editor and add the @@ -119,7 +111,7 @@ following method: sub make_book_widget { my ($self, $c) = @_; - + # Create an HTML::Widget to build the form my $w = $c->widget('book_form')->method('post'); @@ -134,20 +126,18 @@ following method: $w->element('Select', 'authors')->label('Authors') ->options(@authors); $w->element('Submit', 'submit' )->value('submit'); - + # Return the widget return $w; } -This method provides a central location (so it can be called by multiple -actions, such as create and edit) that builds an HTML::Wiget-based form -with the appropriate fields. The "Get Authors" code uses DBIC to -retrieve a list of model objects and then uses C to quickly create -a hash where the hash keys are the database primary keys from the -authors table and the associated values are the last names of the +This method provides a central location that builds an HTML::Widget- +based form with the appropriate fields. The "Get Authors" code uses +DBIC to retrieve a list of model objects and then uses C to create +a hash where the hash keys are the database primary keys from the +authors table and the associated values are the last names of the authors. - =head2 Add Actions to Display and Save the Form Open C in your editor and add the @@ -204,7 +194,6 @@ following methods: # Use 'hw_create' to redisplay the form $c->detach('hw_create'); - } Note how we use C to build the core parts of the form @@ -214,7 +203,6 @@ so allows us to have the same form submit the data to different actions (e.g., C for a create operation but C to update an existing book object). - =head2 Update the CSS Edit C and add the following lines to the bottom of @@ -245,19 +233,18 @@ These changes will display form elements vertically and also show error messages in red. Note that we are pulling the color scheme settings from the C file that was created by the TTSite helper. This allows us to change the color used by various error styles -in the CCS from a single location. - +in the CSS from a single location. =head2 Create a Template Page To Display The Form -C +Open C in your editor and enter the following: + [% META title = 'Create/Update Book' %] [% widget_result.as_xml %]

Return to book list

- =head2 Add Links for Create and Update via C Open C in your editor and add the following to @@ -269,7 +256,6 @@ the bottom of the existing file: Update

- =head2 Test The Create Form Press C to kill the previous server instance (if it's still @@ -290,7 +276,7 @@ bogus information. Although we have constrained the authors with the drop-down list, 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 (you can use any number you want, and even non-numeric values -with SQLite). The next section seeks to address this concern. +with SQLite). The next section will address this concern. B Depending on the database you are using and how you established the columns in your tables, the database could obviously provide various @@ -298,7 +284,6 @@ levels of "type enforcement" on your data. The key point being made in the previous paragraph is that the I itself is not performing any validation. - =head1 C VALIDATION AND FILTERING Although the use of L in the previous section @@ -310,7 +295,6 @@ form contains a valid email address). Filtering can be used to remove extraneous whitespace from fields or to escape meta-characters in user input. - =head2 Add Constraints and Filters to the Widget Creation Method Open C in your editor and update the @@ -319,7 +303,7 @@ been marked with a C<*** NEW:> comment): sub make_book_widget { my ($self, $c) = @_; - + # Create an HTML::Widget to build the form my $w = $c->widget('book_form')->method('post'); @@ -327,7 +311,7 @@ been marked with a C<*** NEW:> comment): my @authorObjs = $c->model("MyAppDB::Author")->all(); my @authors = map {$_->id => $_->last_name } sort {$a->last_name cmp $b->last_name} @authorObjs; - + # Create the form feilds $w->element('Textfield', 'title' )->label('Title')->size(60); $w->element('Textfield', 'rating' )->label('Rating')->size(1); @@ -376,7 +360,6 @@ Two filters are run on every field to remove and escape unwanted input. =back - =head2 Rebuild the Form Submission Method to Include Validation Edit C and change C to @@ -446,6 +429,8 @@ now has a C<$c-Estash-E{template}> line). Note that if we process the form in C I forward/detach back to , we would end up with C being called twice, resulting in a duplicate set of elements being added to the form. +(There are other ways to address the "duplicate form rendering" issue -- +just be aware that it exists.) =item * @@ -463,10 +448,10 @@ similar to the prior version of the C method. =back - =head2 Try Out the Form -Press C to kill the previous server instance (if it's still running) and restart it: +Press C to kill the previous server instance (if it's still +running) and restart it: $ script/myapp_server.pl @@ -488,7 +473,7 @@ model classes: =item * -fill_wiget() +fill_widget() Takes data from the database and transfers it to your form widget. @@ -504,7 +489,6 @@ records in the database. In other words, the two methods are a mirror image of each other: one reads from the database while the other writes to the database. - =head2 Add C to DBIC Model In order to use L, we @@ -515,7 +499,6 @@ C and update the C line to match: __PACKAGE__->load_components(qw/PK::Auto Core HTMLWidget/); - =head2 Use C in C Edit C and update C to @@ -577,16 +560,186 @@ C does not currently handle the relationships between tables. +=head2 Try Out the Form -=head1 AUTHOR +Press C to kill the previous server instance (if it's still +running) and restart it: -Kennedy Clark, C + $ script/myapp_server.pl + +Try adding a book that validate. Return to the book list and the book +you added should be visible. + + + +=head1 Rendering C Forms in a Table + +Some developers my wish to use the "old-fashioned" table style of +rendering a form in lieu of the default C rendering that +assumes you will use CSS for formatting. + + +=head2 Add a New "Element Container" + +Open C in your editor and enter: + + package FormElementContainer; + + use base 'HTML::Widget::Container'; + + sub _build_element { + my ($self, $element) = @_; + + return () unless $element; + if (ref $element eq 'ARRAY') { + return map { $self->_build_element($_) } @{$element}; + } + my $e = $element->clone; + my $class = $e->attr('class') || ''; + $e = new HTML::Element('span', class => 'fields_with_errors')->push_content($e) + if $self->error && $e->tag eq 'input'; + + return $e ? ($e) : (); + } + + 1; + +This simply dumps the HTML code for a given form element, followed by a +C that can contain validation error message. + + +=head2 Enable the New Element Container When Building the Form -Please report any errors, issues or suggestions to the author. +Open C in your editor. First add a +C for your element container class: -Copyright 2006, Kennedy Clark. All rights reserved. + use FormElementContainer; -This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. +Then tell C to use that class during rendering by updating +C to match the following: + + sub make_book_widget { + my ($self, $c) = @_; + + # Create an HTML::Widget to build the form + my $w = $c->widget('book_form')->method('post'); + + # ***New: Use custom class to render each element in the form + $w->element_container_class('FormElementContainer'); + + # Get authors + my @authorObjs = $c->model("MyAppDB::Author")->all(); + my @authors = map {$_->id => $_->last_name } + sort {$a->last_name cmp $b->last_name} @authorObjs; + + # Create the form feilds + $w->element('Textfield', 'title' )->label('Title')->size(60); + $w->element('Textfield', 'rating' )->label('Rating')->size(1); + # Convert to multi-select list + $w->element('Select', 'authors')->label('Authors') + ->options(@authors)->multiple(1)->size(3); + $w->element('Submit', 'submit' )->value('submit'); + + # Set constraints + $w->constraint(All => qw/title rating authors/) + ->message('Required. '); + $w->constraint(Integer => qw/rating/) + ->message('Must be an integer. '); + $w->constraint(Range => qw/rating/)->min(1)->max(5) + ->message('Must be a number between 1 and 5. '); + $w->constraint(Length => qw/title/)->min(5)->max(50) + ->message('Must be between 5 and 50 characters. '); + + # Set filters + for my $column (qw/title rating authors/) { + $w->filter( HTMLEscape => $column ); + $w->filter( TrimEdges => $column ); + } + + # Return the widget + return $w; + } + +The two new lines are marked with C<***New:>. + + +=head2 Update the TT Template + +Open C and edit it to match: + + [% META title = 'Create/Update Book' %] + + [%# Comment out the auto-rendered form %] + [%# widget_result.as_xml %] + + + [%# Iterate over the form elements and display each -%] +
+ + [% FOREACH element = widget_result.elements %] + + + + + [% END %] +
+ [% element.label.as_text %] + + [% element.element_xml %] + + [% element.error_xml %] + +
+
+ + +

Return to book list

+ + + [%# A little JavaScript to move the cursor to the first field %] + + +This represents three changes: + +=over 4 + +=item * + +The existing C has been commented out. + +=item * + +It loops through each form element, displaying the field name in the +first table cell along with the form element and validation errors in +the second field. + +=item * + +JavaScript to position the user's curson in the first field of the form. + +=back + + +=head2 Try Out the Form + +Press C to kill the previous server instance (if it's still +running) and restart it: + + $ script/myapp_server.pl + +Try adding a book that validate. Return to the book list and the book +you added should be visible. + + +=head1 AUTHOR + +Kennedy Clark, C -Version: .94 +Please report any errors, issues or suggestions to the author. The +most recent version of the Catlayst Tutorial can be found at +L. +Copyright 2006, Kennedy Clark, under Creative Commons License +(L).