FAPI/CCK Confusion: 'value' vs '#value'

How CCK uses lots of advanced Form API (FAPI) voodoo to build out the details of its fields during the #process part of FAPI processing.

Angie Byron wrote a nice article on Drupal.org that explains something about how to form_alter CCK fields. At the very end it says:

No, you didn't read that wrong. Sometimes you need to set both ['value']['#value'] and ['#value']['value']. And other times you need to change the field value in $form_state['values']. It seems to be that one controls the value displayed on the form, and the other affects the value sent to the database. You need both to avoid NULL values and "Value is required for field blah blah blah" errors. If anyone can shed some light on what the heck is going on here, that would be awesome. ;P

The short take-away is that CCK uses lots of advanced Form API (FAPI) voodoo to build out the details of its fields during the #process part of FAPI processing. If you want to see what CCK has added to the node form and alter it, you will need to jump in using the #after_build step, which will bring you into the form after #process has finished. But #after_build contains a additional information you won't see in hook_form_alter(). The form looks different at that point because it has now been processed. You will see some parts that look the same as you would expect to see in a hook_form_alter():


...
$form['field_text'][0] = array(
  'value' => array(
    '#type' => 'textfield',
    '#default_value' => 'President',
    '#title' => 'My Title',
  ),
);
$form['field_number'][0] = array(
  'value' => array(
    '#type' => 'textfield',
    '#default_value' => 30,
    '#title' => 'Years of service',
  ),
);
....

The value item here is the name of the field itself. Many CCK fields store something in a column called value': text fields, number fields, email fields, etc. Other CCK fields use different column names, nodereference fields store their values in a column called nid and userreference fields store values in a column called uid. As used in the snippet above, value is the name of the column that a CCK textfield is stored in. If you were processing a form that looks like this in hook_form_alter(), before #process has been invoked, you would set a value for the field in the item called #default_value. In this example we have a field that was set to have a default value of President. But during the #process stage of FAPI processing a final value for the field will be set, and it will be transferred to an array called #value. So the form has picked up additional information by the time we get to #after_build:

  
...
$form['#value']['field_text'][0]['value'] = 'President';
$form['#value']['field_number'][0]['value'] = 30;
    
  

In other words, FAPI has added an array called #value that contains the resolved values for each item. The important thing to note is that if you want to alter the final value for these fields at this point, making changes to #default_value will have no effect at all, the values have already been transferred to the #value array, which is what FAPI considers the final value of these elements. To change these values in #after_build, you need to do something like this:


$form['#value']['field_text'][0]['value'] = 'Secretary';
$form['#value']['field_number'][0]['value'] = 15;
?>  

That will set the right values in the form state for FAPI. But even with that the values that appear in the form that the user sees may still look wrong. Depending on the specific field you are trying alter, you also may need to do the following to make the form look right:


$form['field_text'][0]['value']['#value'] = 'Secretary';
$form['field_number'][0]['value']['#value'] = 15;

Confusing? You bet! As if that wasn't confusing enough, there is one more FAPI value/#value confusion, one that has nothing to do with CCK. FAPI provides a field type called value, and its value is set by #value. This is an alternative to a element type of textfield or select or hidden, it's an element that contains a value that the end user will not see and cannot alter. It's a very handy alternative to a hidden field that can contain anything, even an object or an array (hidden fields can only contain strings). It looks like this:

  
$form['secret_unchangeable_value'] = array(
  '#type' => 'value',
  '#value' => 'Hidden value that no one can see.',
);

If you happened to have something like this in your CCK form, along with all the other value's and #value's.... well, you get the idea. It would be nice if value didn't have all these different meanings to CCK and FAPI. But CCK and FAPI emerged at about the same time and it just happened that both of them used that term for their own purposes.

Published in:

Get in touch with us

Tell us about your project or drop us a line. We'd love to hear from you!