Fieldsets and Drupal settings forms

Blame my lack of experience with Drupal. This week I was held up on a weird problem, and for once the online documentation didn’t seem to be helping.

I was coding a module, with a number of parameters. To keep things tidy, I decided to group them in fieldsets. And, not being too clear on the consequences, I set those fieldsets’ #tree parameter to TRUE. Here’s what it looked like:

Blame my lack of experience with Drupal. This week I was held up on a weird problem, and for once the online documentation didn’t seem to be helping.

I was coding a module, with a number of parameters. To keep things tidy, I decided to group them in fieldsets. And, not being too clear on the consequences, I set those fieldsets’ #tree parameter to TRUE. Here’s what it looked like (simplified example):

function foomodule_admin_settings() {
  $form['foo'] = array('#type' => 'fieldset', '#title' => t('Foo'), '#tree' => TRUE);

  $form['foo']['testmodule_bar'] = array('#type' => 'checkbox',
    '#title' => t('Bar'),
    '#description' => 'Bar',
  );

  $form['foo']['testmodule_baz'] = array('#type' => 'textfield',
    '#title' => t('Baz'),
    '#size' => 20,
    '#description' => t('Baz'));
    

  return system_settings_form($form);
}

What I found then was that the settings wouldn’t save. There were no errors, I got the normal message that “The configuration options have been saved.” but the values in the form were not updated.

After a bit of experimentation and reading up on how Drupal saves these settings, I figured out that the message was correct: my options really were saved, but not in the way I expected.

First, Drupal saves persistent variables in a table, named variable. Each record in this table has two fields: name and value. This field doesn’t exactly hold the value: for some reason Drupal also stores its type and (if it’s a string or array) its length. So (ignoring fieldsets for the moment) the value field for variable “bar” might be

b:1;

(“b” for “boolean”)

—while the value for “baz” could be

s:8:"whatever";

(“s” for “string”)

Apparently, if you’re editing these fields manually, you have to be really careful to make the stored length match the value’s actual length, or Bad Things will happen.

So here’s what it looks like is happening: if a form element is set to '#tree' => TRUE, its child elements’ values will not be stored in the database. Instead, it will get its own line in the variable table, with the value being an array of its child elements’ values. Which here, would look something like this:

a:2:{s:3:"bar";b:1;s:3:"baz";s:8:"whatever";}

This behaviour makes sense, but it seems to break everything about persistent variables. Fortunately there’s a simple solution. Just don’t set ‘#tree’ to TRUE, and the form elements’ values will store correctly. There we go, easy-peasy.

Comments are closed.