I have found a problem with FAPI and multistep forms. In a multistep form, if the user enters data that fails validation, FAPI correctly highlights this to the user. However, when the user re-submits the form, FAPI incorrectly loads the form, and so validates incorrectly.

I've attached a test case module. It's a variant of another testcase module I've submitted before, so ignore most of the on-screen text. The basic flow is this:

1) View page 1
2) Move to page 2 (having entered anything, or nothing into page 1)
3) Page 2 is correctly displayed. The text box is validated to only accept numbers. Enter something non-numeric (eg. the word "hello")
4) Submit the form. FAPI correctly displays an error.
5) Ensure "hello" is still in the number field and re-submit. The form will be accepted.

Actually, at step 5, FAPI loads page 1 of the form, and uses that for validation. It appears that the $form_values from the step 2 form are not passed to this form as it's loaded. As far as I can tell, no form_values are passed, implying it's not loaded as the result of a submit.

I'm sorry to say that this bug seems pretty terminal. With it in place, multi-step forms in Drupal 5.1 seem pretty much unusable. As a result, I'm calling this bug critical (but appreciate it's not critical to "ordinary users").

I'm looking into how to fix it, but I don't hold out much hope (having tried to fiddle with FAPI before!). I'll be trying Drupal 6, but that'll take me some time.

CommentFileSizeAuthor
#6 testcase6_0.tgz20 KBcoofercat
testcase-module2.tgz3.11 KBcoofercat

Comments

shunting’s picture

Thanks. Is this a consquence of FAPI, or of the form being themed? (I worked on a multistep form, and found I had to look to $_POST for what I needed, as opposed to $form_values.

coofercat’s picture

Interesting... No, it looks like it's FAPI not theming (unless there's something really wierd going on - the testcase doesn't do any clever theming). Say you have something like:

function testcase_menu($may_cache) {
  $items = array();
  if($may_cache) {
    $items[] = array(
      'path' => 'testcase',
      'title' => t('FAPI Test Case'),
      'description' => t('Demonstrate A Problem with Checkboxes'),
      'callback' => 'drupal_get_form',
      'callback arguments' => 'testcase_form',
      'access' => user_access('use testcase module'),
      'type' => MENU_NORMAL_ITEM,
    );
  }
  return $items;
}

...then you'd expect a function called "testcase_form" to be called with $form_values either set to NULL or as an array. If an array, then it ought to include all the values posted on the last submit from the user. That array seems to be incomplete (well, empty), so FAPI ends up loading the wrong form, which then means it's not possible to validate/submit the data. As I say, it only seems to happen after a validation failure (first submit works just fine, so long as you make no mistakes).

shunting’s picture

Hi--

SInce checkboxes and their discontents have been a sore spot in CCK, I thought I'd check with a radio button. Adding this to the form:

$form['radio'] = array(
'#type' => 'radios',
'#title' => t('Demo Radio'),
'#default_value' => 'off',
'#options' => array(
'on' => t('On'),
'off' => t('Off'),
),
);

And yes, even if On is selected, the form reverts to the default, Off, on returning to the first page after validation.

BTW I'm using the nice multistep form here, thank you, but not having any problems (except those that I cause for myself). I'm preserving radio buttons across steps, but I'm guessing that's because:

1. I'm not using hook_validate

2. I'm not using hook_form (the form building function is called directly from hook_menu in a callback).

(And it would be really unfortunate, I think, this problem couldn't be fixed from Drupal 5, or FAPI upgraded standalone. Not everyone is going to want to upgrade to 6, and leaving the bug in is going to cause other non-core solutions to proliferate...)

coofercat’s picture

All form elements need a bit of thinking about across multistep forms, but most can be manipulated by correcting #default_value (except checkboxes). Given this FAPI issue, avoid textfield and textarea elements, because they'll need more careful validation than is possible (actually, if you put all your text elements on page 1, you could work around this issue)

I personally haven't used hook_form or hook_validate - my forms are all standalone, so generate whole forms themselves, not as part of some other node module.

I agree about patching up 5.1. I've had a look at FAPI (for the checkbox issue above) and concluded I couldn't make it work. Having had another look, I can't immediately see how/why the wrong form gets loaded in this case either. I'll keep looking, and obviously will post a patch if I get anywhere.

That said, keep an eye on Pre-Emptive's Website - I have a funny feeling that wizard.module will appear there soon (even though it's got limited use on Drupal 5.1) ;-)

shunting’s picture

Well, wizard.module sounds neat...

My thought for what I'm doing in 5 is that what I ought to do is consolidate the operation of the entire form state machine into one function and use $_SESSION for the store, but you know how it is: There's never time to do it right, but there's always time to do it over.

And hopefully the FAPI people will come up with a solution for 5.

coofercat’s picture

StatusFileSize
new20 KB

I'm 99% certain this is solved in Drupal 6. I've attached a testcase which shows it working. I'm a little nervous however, because the testcase is pretty simple, and my application is pretty complex - until I've tested that, I'm a bit scared of commitment ;-) I'll be a while, but I'll confirm when I know.

coofercat’s picture

This looks a lot like anothe thread (which I didn't find before I started this one!).

Multi Part forms after failing validate function, return to first step on submit.

treksler’s picture

Is this confirmed fixed in Drupal 6?

coofercat’s picture

I'm reluctant to confirm beyond all doubt, but certainly, I have had a more complex form running on D6 and it works as expected.

So yes, I think this is fixed in Drupal 6. I am aware of other FAPI issues in D6 (which don't appear to be getting fixed), which may have implications, so be careful.

Berto’s picture

In Drupal 5.x, the best workaround I can think of is this:

function _whatever_form_validate($form_id, $form_values) {
$current_step_to_check = $form_values['step'] -1;
if($current_step_to_check == 1) {
form_set_error("ERROR MESSAGE HERE - WONT SHOW UP");
drupal_set_message("ERROR MESSAGE HERE - WILL SHOW UP");
} else {
// Check the rest or whatever...
}
}

form_set_error will make sure that you don't even MAKE it to the second page. However, drupal_set_message will come through.

The only problem with this is that it's not in red. Oh well.

sun’s picture

Status: Active » Closed (won't fix)

Form API has been entirely revamped for Drupal 6, and once again revamped for Drupal 7. This issue cannot be fixed.