=head1 NAME
-
-
-Catalyst::Manual::Tutorial::AdvancedCRUD::FormFu - Catalyst Tutorial - Part 9: Advanced CRUD - FormFu
+Catalyst::Manual::Tutorial::AdvancedCRUD::FormFu - Catalyst Tutorial - Chapter 9: Advanced CRUD - FormFu
=head1 OVERVIEW
-This is B<Part 9 of 10> for the Catalyst tutorial.
+This is B<Chapter 9 of 10> for the Catalyst tutorial.
L<Tutorial Overview|Catalyst::Manual::Tutorial>
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.03006.
+using HTML::FormFu version 0.03007.
See
L<Catalyst::Manual::Tutorial::AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
L<HTML::FormFu|HTML::FormFu>.
-=head1 Install C<HTML::FormFu>
+=head1 Install HTML::FormFu
-If you are following along in Ubuntu, it turns out that C<HTML::FormFu>
-is not yet available as a package at the time this was written. To
-install it with a combination of C<apt-get> packages and traditional
-CPAN modules, first use C<apt-get> to install most of the modules
-required by C<HTML::FormFu>:
+If you are following along in Debian 5, it turns out that some of the
+modules we need are not yet available as Debian packages at the time
+this was written. To install it with a combination of Debian packages
+and traditional CPAN modules, first use C<aptitude> to install most of
+the modules:
- sudo apt-get install libtest-nowarnings-perl libdatetime-format-builder-perl \
- libdatetime-format-strptime-perl libdatetime-locale-perl \
- libhtml-tokeparser-simple-perl liblist-moreutils-perl \
- libregexp-copy-perl libregexp-common-perl libyaml-syck-perl libparams-util-perl \
- libcrypt-des-perl libcaptcha-recaptcha-perl libcrypt-cbc-perl \
- libreadonly-xs-perl libmoose-perl libregexp-assemble-perl
-
+we need to install the
+L<HTML::FormFu|HTML::FormFu> package:
+
+ sudo aptitude -y install libhtml-formfu-perl libmoose-perl \
+ libregexp-assemble-perl libhtml-formfu-model-dbic-perl
+
...
- sudo apt-get clean
+ sudo aptitude clean
Then use the following command to install directly from CPAN the modules
-that aren't available as Ubuntu/Debian packages via C<apt-get>:
+that aren't available as Debian packages:
- sudo cpan File::ShareDir Task::Weaken Config::Any Test::Harness Test::Aggregate \
- boolean Test::MockTime DateTime::Format::Natural HTML::FormFu \
- Catalyst::Component::InstancePerContext Catalyst::Controller::HTML::FormFu \
- HTML::FormFu::Model::DBIC
-
- ...
-
- Is it OK to try to connect to the Internet? [yes] yes
-
- ...
-
+ sudo cpan Catalyst::Component::InstancePerContext Catalyst::Controller::HTML::FormFu
-B<Note:> If you are following along with the Ubuntu LiveCD, you might
-want to make sure you still have adequate free disk space in the root
-partition with the C<df> command. You can free up some space with
-C<rm -rf /root/.cpan/*>.
-
-=head1 C<HTML::FormFu> FORM CREATION
+=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 Part 4.
+add additional functionality to the manually created form from Chapter 4.
-=head2 Inherit From C<Catalyst::Controller::HTML::FormFu>
+=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 base> line from the default of:
+by changing the C<use parent> line from the default of:
use parent 'Catalyst::Controller';
=cut
- sub formfu_create :Local :FormConfig {
+ 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
# Create a new book
my $book = $c->model('DB::Books')->new_result({});
# Save the form data for the book
- $form->save_to_model($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('list'));
+ $c->response->redirect($c->uri_for($self->action_for('list')));
$c->detach;
} else {
# Get the authors from the DB
- my @authorObjs = $c->model("DB::Authors")->all();
+ my @author_objs = $c->model("DB::Authors")->all();
# Create an array of arrayrefs where each arrayref is an author
my @authors;
- foreach (sort {$a->last_name cmp $b->last_name} @authorObjs) {
+ foreach (sort {$a->last_name cmp $b->last_name} @author_objs) {
push(@authors, [$_->id, $_->last_name]);
}
# Get the select added by the config file
Edit C<root/static/css/main.css> and add the following lines to the bottom of
the file:
+ ...
input {
display: block;
}
[%# Render the HTML::FormFu Form %]
[% form %]
- <p><a href="[% c.uri_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>
Open C<root/src/books/list.tt2> in your editor and add the following to
the bottom of the existing file:
+ ...
<p>
HTML::FormFu:
- <a href="[% c.uri_for('formfu_create') %]">Create</a>
+ <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.
-=head2 Test The <HTML::FormFu> Create 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:
performing any validation.
-=head1 C<HTML::FormFu> VALIDATION AND FILTERING
+=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
=cut
- sub formfu_edit :Local :FormConfig('books/formfu_create.yml') {
- my ($self, $c, $id) = @_;
+ sub formfu_edit :Chained('object') :PathPart('formfu_edit') :Args(0)
+ :FormConfig('books/formfu_create.yml') {
+ my ($self, $c) = @_;
- # Get the specified book
- my $book = $c->model('DB::Books')->find($id);
+ # 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('list'));
+ $c->response->redirect($c->uri_for($self->action_for('list')));
$c->detach;
}
# is shorthand for "$form->submitted && !$form->has_errors"
if ($form->submitted_and_valid) {
# Save the form data for the book
- $form->save_to_model($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('list'));
+ $c->response->redirect($c->uri_for($self->action_for('list')));
$c->detach;
} else {
# Get the authors from the DB
- my @authorObjs = $c->model("DB::Authors")->all();
+ my @author_objs = $c->model("DB::Authors")->all();
# Create an array of arrayrefs where each arrayref is an author
my @authors;
- foreach (sort {$a->last_name cmp $b->last_name} @authorObjs) {
+ foreach (sort {$a->last_name cmp $b->last_name} @author_objs) {
push(@authors, [$_->id, $_->last_name]);
}
# Get the select added by the config file
# Add the authors to it
$select->options(\@authors);
# Populate the form with existing values from DB
- $form->defaults_from_model($book);
+ $form->model->default_values($book);
}
# Set the template
=item *
-We accept C<$id> as an argument via the URL.
+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 use C<$id> to look up the existing book from the database.
+We load the book object from the stash (found using the $id passed to
+the Chained object method)
=item *
-We make sure the C<$id> and book lookup returned a valid book. If not,
-we set the error message and return to the book list.
+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.
+
=item *
If the form has been submitted and passes validation, we skip creating a
-new book and just use C<$form-E<gt>save_to_model> to update the existing
+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
validation and it being redisplayed), we use
- C<$form-E<gt>default_from_model> to populate the form with data from the
+ C<$form-E<gt>model-E<gt>default_values> to populate the form with data from the
database.
=back
...
<td>
[% # Add a link to delete a book %]
- <a href="[% c.uri_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('formfu_edit', book.id) %]">Edit</a>
+ <a href="[% c.uri_for(c.controller.action_for('formfu_edit'), [book.id]) %]">Edit</a>
</td>
...
green. Experiment with other edits to various books.
+=head2 More Things to Try
+
+You are now armed with enough knowledge to be dangerous. You can keep
+tweaking the example application; some things you might want to do:
+
+=over 4
+
+=item *
+
+Add an appropriate authorization check to the new Edit function.
+
+=item *
+
+Cleanup the List page so that the Login link only displays when the user
+isn't logged in and the Logout link only displays when a user is logged
+in.
+
+=item *
+
+Add a more sensible policy for when and how users and admins can do
+things in the CRUD cycle.
+
+=item *
+
+Support the CRUD cycle for authors.
+
+=back
+
+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
If you are having difficulty with YAML config above, please save the
indicator submit
-
=head1 AUTHOR
Kennedy Clark, C<hkclark@gmail.com>
most recent version of the Catalyst Tutorial can be found at
L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-Copyright 20066-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
-
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).