[development] Forms API and #required file fields

Barry Jaspan barry at jaspan.org
Fri Jun 2 17:16:36 UTC 2006


The Forms API does not currently support file fields with #required 
=> TRUE (and is documented as such in the Forms API Reference).  I 
suggest that with a little effort it can and that to make the API 
more consistent and useful it should.

I discovered this limitation because 4.7 flexinode allows file, 
image, and perhaps other file-based fields to be specified as 
required and attempts to impose the required-ness by setting 
#required => TRUE in the form element.  The result is a flexinode 
type that cannot be created or edited because all #required file 
fields are always reported as not filled in, even if they 
are.   Clearly, this is a bug in flexinode, not in the Forms API 
which is just behaving as specified.  However, the fact that 
flexinode tried to work this way argues that the Forms API SHOULD 
support it, because it is a logical and consistent way to interpret 
Forms API semantics.

The reason it doesn't work is that form_builder() in form.inc only 
looks in $_POST for values to store in $form['#value'].  Since file 
upload data is in $_FILES, $form['#value'] is never set for file 
fields.  When it is #required, _form_validate() reports an error.

form_builder() already has a switch based on $form['#type'].  We 
could add something like:

   case 'file':
      $form['#value'] = $_FILES['edit']['name'][$form['#key']];
      break;

The new $form['#value'] would then have a filename if one were 
uploaded or nothing if one were not.  This would be sufficient to 
support the #required field.  Since currently $form['#value'] never 
contains anything for file fields, storing a filename there can't hurt anybody.

This requires that $form['#key'] be set so a form element knows its 
own name in the $_POST and $_FILES arrays.  But that is easy enough 
to do during the recursion in form_builder():

   // Recurse through all child elements.
   $count  = 0;
   foreach (element_children($form) as $key) {
      // tell each element its own key name
      $form[$key]['#key'] = $key;

      ....
   }

Comments?  I'll implement this if the change will be accepted.

Barry



More information about the development mailing list