This one has me a little confused. The goal is to take in a couple of parameters from a form and then output some results along side the original form. This is a super-basic task that seems surprisingly hard in drupal.
Here are some ways to do this that I have come up with (in order of complexity):
1) Simplest way: On submit, stuff the results into the page with a bunch of drupal_set_messages.
<?php
function find_path_form() {
$form = ...build the form array...
return $form;
}
function find_path_form_submit($form_id, $form_values) {
$path = $form_values['path'];
drupal_set_message( find_path_results($path) );
return false;
}
?>Disadvantages: Can't control where there results show up. Not really what drupal_set_message is intended for.
2) Look at the $_POST in form builder function (I got this one from Doug Green).
<?php
function find_path_form() {
$form = ...build the form array...
$path = $_POST['path'];
if( isset($path) ) {
$form['results'] = array(
'#value' => find_path_results($path),
);
}
return $form;
}
function find_path_form_submit($form_id, $form_values) {
return false;
}
?>Disadvantages: The formAPI guys want us to stop looking at $_POST for security reasons.
3) Use $form_values in the _form_submit
<?php
function find_path_form() {
$form = ...build the form array...
return $form;
}
function find_path_form_submit($form_id, $form_values) {
$path = $form_values['path'];
$form = drupal_retrieve_form( 'find_path_form' );
drupal_prepare_form( 'find_path_form', $form );
$output .= drupal_render_form( 'find_path_form', $form );
$output .= find_path_results($path);
print theme( 'page', $output );
exit; // need to exit to avoid "cannot modify headers" error
}
?>Disadvantages: You need to exit out of the _form_submit function to avoid the automatic goto. This seems to work fine, but makes me uncomfortable.
4) Encode the params in a url: this is the technique used by the search module. This is the only one that doesn't feel like a hack.
<?php
function find_path_form() {
$form = ...build the form array...
return $form;
}
function find_path_form_submit($form_id, $form_values) {
$path = $form_values['path'];
return "find_path/$path";
}
// mapped to by new menu callback w/arg
function find_path_view($path) {
$output = drupal_get_form( 'find_path_form' );
$output .= find_path_results( $path );
return $output;
}
?>Disadvantages: Can get really complex if you need to pass multiple form parameters. Can't cache menu item. Also tricky to keep tabs in place.
5) Put the parameters into the session in _form_submit, then access them in the form_theme function - this is cute, and it works, but is just overly complicated.
That's all I have been able to think off. Personally I lean towards #3 as having the clearest logic to follow. But it really seems like there should be an easier/cleaner way than any of them. So, am I missing something obvious?
Check out SQL Search module
Basically, they build the search submit form in the typical fashion, but include an #after_build directive to call the function that renders the current search results, and an #action directive to keep submits posting to the same path. Functions called by #after_build get passed in $form and $form_values, just like a form submit handler.
Brad Banister
$form_state in Drupal 6
In Drupal 6, you can also use $form_state['rebuild'] and $form_state['storage'], to rebuild the form along side with the results.
<?php function find_path_form(&$form_state){$form = ...build the form array...
// show results if exists in $form_state['storage']
if(isset($form_state['storage']['results'])) {
$form['results'] = array(
'#value' => $form_state['storage']['results']
);
}
return $form;
}
function
find_path_form_submit($form_id, &$form_state){// get submited parameters
$submitedParams = $form_state['values'];
// custom function to query database ang return results
$results = find_path_results( $submitedParams );
// rebuilds form
$form_state['rebuild'] = TRUE;
// pass results to form
$form_state['storage']['results'] = $results ;
} ?>
Note that if $form_state['storage'] is populated, $form_state['rebuild'] is automatically set to TRUE.