[Catalyst] CatalystX::CRUD::Controller::RHTMLO: related database
tables and nested forms
John Siracusa
siracusa at gmail.com
Wed Jan 13 16:30:52 GMT 2010
On Wed, Jan 13, 2010 at 10:33 AM, Adam Mackler <nabble at mackler.org> wrote:
> First, his solution won't work with CatalystX::CRUD. He has his
> method called "person_from_form" that returns a Rose::DB::Object that
> was created from the Rose::HTML::Form, and that DB object contains the
> references to the related objects created from the related, nested
> forms. That's just what I want! The problem is that his
> person_from_form() method takes no arguments (besides the caller),
> whereas I am using CatalystX::CRUD::Controller::RHTMLO, which calls
> person_to_form() and expects to be able to pass to a it Person object
> in order to update that object. So his solution, which doessn't do
> such updating, does't work with CatalystX::CRUD::Controller::RHTMLO.
Ignoring Catalyst for a moment, here are some general patterns for
CRUD with RHTMLO (error handling omitted):
* Show empty creation form:
# Get form object:
# Either create a new one:
$form = MyForm->new;
# or grab an existing one ans reset it:
#$form = GetMyForm();
#$form->reset();
# Initialize form with query parameters (if any)
$form->params(GetQueryParamsSomehow());
$form->init_fields();
# Show the page with the form on it
ShowCreationPageWithForm($form);
* Handle a "create" form submission:
# Get form object (same as before)
$form = ...
# Initialize form with query parameters (same as before)
...
# Get object form form
$object = $form->my_whatever_from_form();
# Save object;
$object->save;
# Redirect to success page
...
* Show an edit form:
# Get object to be edited
$id = IdFromQueryParameters();
$object = MyObject->new(id => $id)->load;
# Get form object (same as before)
$form = ...
# Initialize form with object
$form->init_with_my_whatever($object);
# Show the edit page with the form on it
ShowEditPageWithForm($form);
* Handle a "update" form submission:
# Get object to be updated (same as before)
$object = ...
# Get form object (same as before)
$form = ...
# Initialize form with query parameters (same as before)
...
# Get the updated object from form:
# (Note that the existing object is passed as an arg.)
$object = $form->my_whatever_from_form($object);
# Save the updated object
$object->save;
# Redirect to success page
...
In all cases, the $object could be a tree of related objects. In
those cases, the load() calls to get an existing $object should use
the load(with => ...) form (or perhaps a Manager call) to get a fully
populated tree of objects.
As you can see, there's a lot of common stuff that can be factored
out. For example, in my web apps, I usually have a set of pre-created
form objects stashed away by name (e.g., create_form, edit_form, etc.)
and a prepare_form() method that does all the form reset()ing and
initialization with params:
# Get form, reset(), and initialized with the current query params
$form = $mywebapp->prepare_form('create_form');
> Second, how hard really would it be to create the functionality I
> want? Can I make my "person_to_form()" method (in my case
> debtor_to_form) go through all its subforms and add the related
> objects? It doesn't seem to me as if it would be too hard (for
> someone competent). I envision something like this in my Debtor Form:
>
> sub debtor_from_form (
> my ($self) = shift;
> my (@args) = @_;
>
> # get the main object for the form
> my $debtor = $self->object_from_form(@args);
>
> # get related object from the related forms
> foreach my $subname ($self->form_names) {
> my $subform = $self->form($subname);
> my $method = $subform->init_object;
> my $sub_object = $subform->$method;
> $debtor->$subname($sub_object);
> }
> return $debtor;
> }
That's the basic idea: delegate sub-object handling to the sub-forms
that know how to handle them. The init_with_db_object() and
db_object_from_form() methods linked to earlier[1] automate this
process as long as you match up the sub-form names with the
relationship/fk names in your RDBO classes.
> But even if that works, there's still the issue of populating the form
> fields when making changes to existing database rows. I wouldn't know
> where to start on that one.
Pass a fully populated object tree to init_with_db_object() and it'll
do this for you by matching up relationship/fk names with sub-form
names. Step through the code to see how it works, and how you could
manually do the same thing.
-John
1. http://www.mail-archive.com/rose-db-object@lists.sourceforge.net/msg01443.html
and bug fix:
http://www.mail-archive.com/rose-db-object@lists.sourceforge.net/msg01464.html
More information about the Catalyst
mailing list