First pass through add form with constraints and filtering. Hope to add edit feature...
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / AdvancedCRUD / FormFu.pod
CommitLineData
b80f58e5 1=head1 NAME
2
3Catalyst::Manual::Tutorial::AdvancedCRUD::FormFu - Catalyst Tutorial - Part 9: Advanced CRUD - FormFu
4
5
c010ae0d 6NOTE: This part of the tutorial is in progress and will be ready soon.
7
b80f58e5 8=head1 OVERVIEW
9
10This is B<Part 9 of 10> for the Catalyst tutorial.
11
12L<Tutorial Overview|Catalyst::Manual::Tutorial>
13
14=over 4
15
16=item 1
17
18L<Introduction|Catalyst::Manual::Tutorial::Intro>
19
20=item 2
21
22L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
23
24=item 3
25
26L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
27
28=item 4
29
30L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
31
32=item 5
33
34L<Authentication|Catalyst::Manual::Tutorial::Authentication>
35
36=item 6
37
38L<Authorization|Catalyst::Manual::Tutorial::Authorization>
39
40=item 7
41
42L<Debugging|Catalyst::Manual::Tutorial::Debugging>
43
44=item 8
45
46L<Testing|Catalyst::Manual::Tutorial::Testing>
47
48=item 9
49
d682d02d 50B<Advanced CRUD::FormFu>
b80f58e5 51
52=item 10
53
54L<Appendices|Catalyst::Manual::Tutorial::Appendices>
55
56=back
57
58
59=head1 DESCRIPTION
60
cca5cd98 61This portion of the tutorial explores L<HTML::FormFu|HTML::FormFu> and
62how it can be used to manage forms, perform validation of form input,
63as well as save and restore data to/from the database.
64
65See
66L<Catalyst::Manual::Tutorial::AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
67for additional form management options other than
68L<HTML::FormFu|HTML::FormFu>.
69
70
71=head1 Install C<HTML::FormFu>
72
73If you are following along in Ubuntu, it turns out that C<HTML::FormFu>
74is not yet available as a package at the time this was written. To
75install it with a combination of C<apt-get> packages and traditional
76CPAN modules, first use C<apt-get> to install most of the modules
77required by C<HTML::FormFu>:
78
79 sudo apt-get install libtest-nowarnings-perl libdatetime-format-builder-perl \
80 libdatetime-format-strptime-perl libdatetime-locale-perl \
81 libhtml-tokeparser-simple-perl liblist-moreutils-perl \
82 libregexp-copy-perl libregexp-common-perl libyaml-syck-perl libparams-util-perl
83
84Then use the following command to install directly from CPAN the modules
85that aren't available as Ubuntu/Debian packages via C<apt-get>:
86
87 sudo cpan File::ShareDir Task::Weaken Config::Any HTML::FormFu \
88 Catalyst::Controller::HTML::FormFu
89
90
91=head1 C<HTML::FormFu> FORM CREATION
92
93This section looks at how L<HTML::FormFu|HTML::FormFu> can be used to
94add additional functionality to the manually created form from Part 4.
95
96
97=head2 Inherit From C<Catalyst::Controller::HTML::FormFu>
98
99First, change your C<lib/MyApp/Controller/Books.pm> to inherit from
100L<Catalyst::Controller::HTML::FormFu|Catalyst::Controller::HTML::FormFu>
101by changing the C<use base> line from the default of:
102
103 use base 'Catalyst::Controller';
104
105to use the FormFu base controller class:
106
107 use base 'Catalyst::Controller::HTML::FormFu';
108
109
110=head2 Add Action to Display and Save the Form
111
112Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
113following method:
114
d682d02d 115 =head2 formfu_create
cca5cd98 116
117 Build an HTML::FormFu form for book creation and updates
118
119 =cut
120
d682d02d 121 sub formfu_create :Local :FormConfig {
cca5cd98 122 my ($self, $c) = @_;
123
124 # Get the form that the :FormConfig attribute saved in the stash
125 my $form = $c->stash->{form};
126
127 # Check if the form as been submitted (vs. displaying the initial
128 # form) and if the data based validation. "submitted_and_valid"
129 # is shorthand for "$form->submitted && !$form->has_errors"
130 if ($form->submitted_and_valid) {
131 # Create a new book
132 my $book = $c->model('DB::Books')->new_result({});
133 # Save the form data for the book
134 $form->save_to_model($book);
135 # Set a status message for the user
136 $c->flash->{status_msg} = 'Book created';
137 # Return to the books list
138 $c->response->redirect($c->uri_for('list'));
139 $c->detach;
9cb64a37 140 } else {
141 # Get the authors from the DB
142 my @authorObjs = $c->model("DB::Authors")->all();
143 # Create an array of arrayrefs where each arrayref is an author
144 my @authors;
145 foreach (sort {$a->last_name cmp $b->last_name} @authorObjs) {
146 push(@authors, [$_->id, $_->last_name]);
147 }
148 # Get the select added by the config file
149 my $select = $form->get_element({type => 'Select'});
150 # Add the authors to it
151 $select->options(\@authors);
152 }
153
cca5cd98 154 # Set the template
d682d02d 155 $c->stash->{template} = 'books/formfu_create.tt2';
cca5cd98 156 }
157
158
159=head2 Create a Form Config File
160
161Although C<HTML::FormFu> supports any configuration file handled by
162L<Config::Any|Config::Any>, most people tend to use YAML. First
163create a directory to hold your form configuration files:
164
165 mkdir -p root/forms/books
166
d682d02d 167Then create the file C<root/forms/books/formfu_create.yml> and enter the
cca5cd98 168following text:
169
170 ---
9cb64a37 171 # indicator is the field that is used to test for form submission
cca5cd98 172 indicator: submit
9cb64a37 173 # Start listing the form elements
cca5cd98 174 elements:
9cb64a37 175 # The first element will be a text field for the title
cca5cd98 176 - type: Text
177 name: title
178 label: Title
9cb64a37 179 # This is an optional 'mouse over' title pop-up
cca5cd98 180 attributes:
181 title: Enter a book title here
d682d02d 182
183 # Another text field for the numeric rating
cca5cd98 184 - type: Text
185 name: rating
186 label: Rating
187 attributes:
188 title: Enter a rating between 1 and 5 here
d682d02d 189
190 # Add a drop-down list for the author selection. Note that we will
191 # dynamically fill in all the authors from the controller but we
192 # could manually set items in the drop-list by adding this YAML code:
193 # options:
194 # - [ '1', 'Bastien' ]
195 # - [ '2', 'Nasseh' ]
196 - type: Select
197 name: authors
198 label: Author
199
9cb64a37 200 # The submit button
cca5cd98 201 - type: Submit
202 name: submit
203 value: Submit
204
205
206=head2 Update the CSS
207
208Edit C<root/src/ttsite.css> and add the following lines to the bottom of
209the file:
210
d682d02d 211 input {
cca5cd98 212 display: block;
213 }
d682d02d 214 select {
cca5cd98 215 display: block;
216 }
d682d02d 217 .submit {
218 padding-top: .5em;
219 display: block;
cca5cd98 220 }
221
d682d02d 222These changes will display form elements vertically. Note that the
223existing definition of the C<.error> class is pulling the color scheme
224settings from the C<root/lib/config/col> file that was created by the
225TTSite helper. This allows control over the CSS color settings from a
226single location.
cca5cd98 227
228
229=head2 Create a Template Page To Display The Form
230
d682d02d 231Open C<root/src/books/formfu_create.tt2> in your editor and enter the following:
cca5cd98 232
233 [% META title = 'Create/Update Book' %]
234
235 [%# Render the HTML::FormFu Form %]
236 [% form %]
237
238 <p><a href="[% Catalyst.uri_for('list') %]">Return to book list</a></p>
239
240
241=head2 Add Links for Create and Update via C<HTML::FormFu>
242
243Open C<root/src/books/list.tt2> in your editor and add the following to
244the bottom of the existing file:
245
246 <p>
247 HTML::FormFu:
d682d02d 248 <a href="[% Catalyst.uri_for('formfu_create') %]">Create</a>
cca5cd98 249 </p>
250
d682d02d 251This adds a new link to the bottom of the book list page that we can
252use to easily launch our HTML::FormFu-based form.
253
cca5cd98 254
d682d02d 255=head2 Test The <HTML::FormFu> Create Form
cca5cd98 256
257Press C<Ctrl-C> to kill the previous server instance (if it's still
258running) and restart it:
259
260 $ script/myapp_server.pl
261
d682d02d 262Login as C<test01>. Once at the Book List page, click the new
263HTML::FormFu "Create" link at the bottom to display the form. Fill in
264the following values: Title = "Internetworking with TCP/IP Vol. II",
265Rating = "4", and Author = "Comer". Click Submit, and you will be
266returned to the Book List page with a "Book created" status message
267displayed.
268
269Also note that this implementation allows you to can create books with
270bogus information. Although we have constrained the authors with the
271drop-down list (somewhat, we still have not prevented a user from
272"hacking" the form to specify other values), there are no restrictions
273on items such as the length of the title (for example, you can create a
274one-letter title) and value for the rating (you can use any number you
275want, and even non-numeric values with SQLite). The next section will
276address this concern.
cca5cd98 277
278B<Note:> Depending on the database you are using and how you established
279the columns in your tables, the database could obviously provide various
280levels of "type enforcement" on your data. The key point being made in
281the previous paragraph is that the I<web application> itself is not
282performing any validation.
283
284
285=head1 C<HTML::FormFu> VALIDATION AND FILTERING
286
d682d02d 287Although the use of L<HTML::FormFu|HTML::FormFu> in the previous section
288did provide an automated mechanism to build the form, the real power of
289this module stems from functionality that can automatically validate and
290filter the user input. Validation uses constraints to be sure that
291users input appropriate data (for example, that the email field of a
292form contains a valid email address). Filtering can also be used to
293remove extraneous whitespace from fields or to escape meta-characters in
294user input.
cca5cd98 295
cca5cd98 296
d682d02d 297=head2 Add Constraints
cca5cd98 298
d682d02d 299Open C<root/forms/books/formfu_create.yml> in your editor and update it
cca5cd98 300to match:
301
302 ---
9cb64a37 303 # indicator is the field that is used to test for form submission
cca5cd98 304 indicator: submit
9cb64a37 305 # Start listing the form elements
cca5cd98 306 elements:
9cb64a37 307 # The first element will be a text field for the title
cca5cd98 308 - type: Text
309 name: title
310 label: Title
9cb64a37 311 # This is an optional 'mouse over' title pop-up
cca5cd98 312 attributes:
313 title: Enter a book title here
d682d02d 314 # Use Filter to clean up the input data
315 filter:
316 # Remove whitespace at both ends
317 - TrimEdges
318 # Escape HTML characters for safety
319 - HTMLEscape
9cb64a37 320 # Add constraints for the field
cca5cd98 321 constraints:
9cb64a37 322 # The user cannot leave this field blank
cca5cd98 323 - Required
d682d02d 324 # Force the length to be between 5 and 30 chars
cca5cd98 325 - type: Length
d682d02d 326 min: 5
cca5cd98 327 max: 30
9cb64a37 328 # Override the default of 'Invalid input'
d682d02d 329 message: Length must be between 5 and 30 characters
330
331 # Another text field for the numeric rating
cca5cd98 332 - type: Text
333 name: rating
334 label: Rating
335 attributes:
336 title: Enter a rating between 1 and 5 here
d682d02d 337 # Use Filter to clean up the input data
338 filter:
339 # Remove whitespace at both ends
340 - TrimEdges
341 # Remove everything except digits
342 - NonNumeric
343 # Add constraints to the field
cca5cd98 344 constraints:
345 - Required
9cb64a37 346 # Make sure it's a number
cca5cd98 347 - Integer
d682d02d 348
349 # Add a select list for the author selection. Note that we will
350 # dynamically fill in all the authors from the controller but we
351 # could manually set items in the select by adding this YAML code:
352 # options:
353 # - [ '1', 'Bastien' ]
354 # - [ '2', 'Nasseh' ]
355 - type: Select
356 name: authors
357 label: Author
358 # Convert the drop-down to a multi-select list
359 multiple: 1
360 # Display 3 entries (user can scroll to see others)
361 size: 3
362 # One could argue we don't need to do filters or constraints for
363 # a select list, but it's smart to do validation and sanity
364 # checks on this data in case a user "hacks" the input
365 # Use Filter to clean up the input data
366 filter:
367 # Remove whitespace at both ends
368 - TrimEdges
369 # Escape HTML characters for safety
370 - HTMLEscape
371 # Add constraints to the field
372 constraints:
373 - Required
374 # Make sure it's a number
375 - Integer
376
9cb64a37 377 # The submit button
cca5cd98 378 - type: Submit
379 name: submit
380 value: Submit
d682d02d 381
9cb64a37 382 # Globally ensure that each field only specified one value
cca5cd98 383 constraints:
384 - SingleValue
385
d682d02d 386The main changes are:
387
388=over 4
389
390=item *
391
392The C<Select> element for C<authors> is changed from a single-select
393drop-down to a multi-select list by adding configuration for the
394C<multiple> and C<size> options in C<formfu_create.yml>.
395
396=item *
397
398Constraints are added to provide validation of the user input. See
399L<HTML::FormFu::Constraint|HTML::FormFu::Constraint> for other
400constraints that are available.
401
402=item *
403
404A variety of filters are run on every field to remove and escape
405unwanted input. See L<HTML::FormFu::Filter|HTML::FormFu::Filter>
406for more filter options.
407
408=back
409
410
411=head2 Try Out the Updated Form
412
413Press C<Ctrl-C> to kill the previous server instance (if it's still
414running) and restart it:
415
416 $ script/myapp_server.pl
417
418Now try adding a book with various errors: title less than 5 characters,
419non-numeric rating, a rating of 0 or 6, etc. Also try selecting one,
420two, and zero authors. When you click Submit, the HTML::FormFu
421C<constraint> items will validate the logic and insert feedback as
422appropriate. Try adding blank spaces at the front or the back of the
423title and note that it will be removed.
424
cca5cd98 425
426=head1 AUTHOR
427
428Kennedy Clark, C<hkclark@gmail.com>
429
430Please report any errors, issues or suggestions to the author. The
431most recent version of the Catalyst Tutorial can be found at
432L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/>.
433
d682d02d 434Copyright 20066-2008, Kennedy Clark, under Creative Commons License
cca5cd98 435(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
436