Today I found myself reworking a set of directory classes I wrote in haste a few months ago. I decided that some of them would gain from making use of DB_DataObject_FormBuilder but had to remind myself of how to make that package work with multiple tables.

The presentation included as part of the documentation demonstrates how to create a form with data from multiple tables, using something like:

$first_table =& DB_DataObject::factory('table_one');
$first_table->fb_createSubmit = false;
$first_build =& DB_DataObject_FormBuilder::create($first_table);
$first_form = $first_build->getForm();

$second_table = DB_DataObject::factory('table_two');
$second_build =& DB_DataObject_FormBuilder::create($second_table);
$second_build->useForm($first_form);

print $second_build->toHTML();

Personally, I’m not a fan of the headers that QuickForm (the form class behind FormBuilder) adds for each table, so after a little hunting around I discovered that:

$first_table->fb_addFormHeader = false;

would get rid of those.

What wasn’t clear from the documentation is how to validate and process the form that is produced from these two tables. I briefly wondered if ‘useForm’ would join the validation and processing terms, but as I suspected it didn’t. If you’re creating new entries for both tables, what you’ll want to do is something like:

if ($first_form->validate() && $second_form->validate()) {
	$first_form->process(array(&$first_build,'processForm'), false);
	$first_table->link_field = $second_table->link_field;
	$second_form->process(array(&$second_build,'processForm'), false);
}

Of course, if you’re using the forms to edit content rather than create new rows in the database, your DataObjects will be pre-loaded with the relevant IDs and so that middle line, setting the keys won’t be necessary.

Aside: I’ve a lot of sympathy with Paul Jones’ comments on HTML_QuickForm and MVC. Right now I’m setting up my forms with the relevant data in the model layer and then passing a reference to the object to the view layer so that it can handle the output. That works okay for now, but if there’s a more elegant solution out there I’d love to know!