I see that $form_state 'input' is used in several places, but it seems those places should be using 'values' instead. Was this by design to get around some problem?

If you submit a form, but the value for the date field is not submitted for some reason, then the default value of the form element is ignored. Instead, the final field value in $form_state['values'] is set NULL in date_popup_validate. Since normally $form_state['values'] is populated with default values if no value is returned, directly using input skips that. I don't know if this problem happens for other widget types too, but it looks likely.

I'm happy to take a stab at this, but I mostly want to make sure I don't end up undoing something that was done on purpose. Please give me your thoughts?

More specifically, in date_popup_validate, this line returns nothing if the field value was not in the POST response.

$input = drupal_array_get_nested_value($form_state['input'], $element['#parents'], $input_exists);

Which eventually will propagate to this, setting the form value to NULL.

form_set_value($element, $value, $form_state);
CommentFileSizeAuthor
#3 l.tar_.gz1.24 KBloganfsmyth
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

KarenS’s picture

'Input' is used to retrieve the values that used to be stored in #post -- the raw posted values. We grab the raw posted values so we can see what elements were chosen or left empty when we populate the end date (values that are left empty are populated with whatever was in the Start date). I don't know that using 'values' will give you the right results, but that is what you have to test.

KarenS’s picture

I'm digging into the usage of 'input' and 'values' to see if changes are needed but am unable to create any situation where they produce different values. I need an explicit example of something where the result is wrong because they are different.

loganfsmyth’s picture

FileSize
1.24 KB

Sure, no problem. As it is right now, there is an assumption that 'input' will have some kind of data for the field. However, with most elements, you expect that, should a field not have any data submitted, then the '#default_value' attribute will take over

This is a more general issue with lots of the date elements, not just the code that I mentioned in my initial post.
Here is an example module. I attached it as a tar as well.

If you view the form normally and submit, then there is no problem and the default value is respected, but when, for some reason or another, there are no submitted values, as with the programmatically submitted form, the value for date is NULL, instead of the default value.

As an example where this comes up, without the need for programmatic submission, try settings '#disabled' => TRUE on the date_text field. Input boxes with the disabled attribute are no submitted by the browser, so when you disable the date box, it's value shows up as NULL even though it had a default value.


/**                                                                                 
 * Implements hook_menu().                                                          
 */                                                                                 
function l_menu() {                                                                 
  return array(                                                                     
    'l' => array(                                                                   
      'type' => MENU_CALLBACK,                                                      
      'page callback' => 'drupal_get_form',                                         
      'page arguments' => array('l_form'),                                          
      'access callback' => TRUE,                                                    
    ),                                                                              
    'l-date-sub' => array(                                                          
      'type' => MENU_CALLBACK,                                                      
      'page callback' => 'l_date_sub_page',                                         
      'access callback' => TRUE,                                                    
    ),                                                                              
  );                                                                                
}                                                                                   
                                                                                    
/**                                                                                 
 * Page callback to run a programmatic submit.                                      
 */                                                                                 
function l_date_sub_page() {                                                        
  $form_state = array(                                                              
    'values' => array(),                                                            
  );                                                                                
                                                                                    
  drupal_form_submit('l_form', $form_state);                                        
                                                                                    
  return 'page content';                                                            
}                                                                                   
                                                                                    
/**                                                                                 
 * Basic form function to test date element.                                        
 */                                                                                 
function l_form($form, &$form_state) {                                              
                                                                                    
  $form['date'] = array(                                                            
    '#type' => 'date_text',                                                         
    '#title' => t('Date'),                                                          
    '#default_value' => '2011-11-08 09:01',                                         
  );                                                                                
                                                                                    
                                                                                    
  $form['submit'] = array(                                                          
    '#type' => 'submit',                                                            
    '#value' => 'Submit',                                                           
  );                                                                                
  return $form;                                                                     
}                                                                                   
                                                                                    
                                                                                    
/**                                                                                 
 * Submit function to demonstrate value of the 'date' field.                        
 */                                                                                 
function l_form_submit($form, &$form_state) {                                       
  dsm($form_state['values']);                                                       
}
KarenS’s picture

Status: Active » Fixed

As a part of the work in [#1179715] I changed a lot of this. I *think* it should be working right now.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

vaughnbullard’s picture

Status: Closed (fixed) » Active

Hi Karen,

I actually am running into an issue where the usage of $form_state[‘input’] vs. $form_state[‘values’] produces different values for no apparent reason. For example, in the following code sample I have a hidden form element called “tcodes”. This is simply to hold a few data elements that are hidden from the user. Nothing encrypted, just a variable for holding some temporary data that I’ll need in the form submission.

    $form['ContactInformation']['tcodes'] = array(
        '#type'             => 'hidden',
        '#value'            => $tcodes,   
        '#size'             => 256,
        '#required'         => FALSE, // Added
    );  

If you’ll notice that this form element called tcodes has no special wrappers or AJAX-based behavior. It is a simple form element. In it, I store a value called “BC-CB11”. Well, given this form element. It should be as simple as calling $form_state[‘values’][‘tcodes’] to retrieve the passed value. Instead of retrieving it as “BC-CB11”, I get a value of “system/ajax”.

Keep in mind that there are no AJAX elements that are used on this page that produces this as I have tested this on its own form with no other form elements. However, if I change this to $form_state[‘input’][‘tcodes’] I am able to retrieve “BC-CB11” with no problems whatsoever. I understand that the ‘input’ part of $form_state retrieves the raw POST data, but it doesn’t make any sense that Drupal should change the value to “system/ajax” for a form or form element that has NO AJAX or JavaScript. In fact, JavaScript was turned off in this case.

This is a perplexing issue to me as there is very little documentation with regard to scenarios where this might happen. Workarounds are fine such as using the $form_state[‘input’][‘tcodes’], but it is only a temporary fix as I would like to be able to make the best use of Drupal’s form API validation mechanisms, etc.

Best Regards,
Vaughn

hussainweb’s picture

I am facing problems with the usage of $form_state['input'] and the only way I have got around it now is by using drupal_array_set_nested_value().

I am trying to implement an alternate calendar but storing the date in a regular fashion after conversion to (regular) gregorian calendar. I have already created the widget that attaches to Date fields. To reuse Date handlers, I explicitly call date_field_widget_form from my hook_field_widget_form implementation and to change the contained widget, I use hook_date_combo_process_alter to change the widget type, otherwise it defaults to date_text, as obviously, date_combo_element_process() does not know about my widget.

This is fine so far. In my widget_validate hooks, I convert the date to gregorian for storage. I checked the sequence and it converts it fine and sets this in $form_state['values'] using form_set_value(). The problem is that eventually date_combo_validate() is called for the parent widget. Here, this line reads the input variables which are used later.

$form_input = drupal_array_get_nested_value($form_state['input'], $element['#field_parents']);
...
$posted = $form_input[$field_name][$langcode][$delta];

The variable $posted is used later to load the date using date_input_date(). This variable, of course, contains values from the actual input (which would have been fine in some cases but this calendar has 29 days in second month which does not sit well with DateObject). I tried looking into hooks but date_combo_pre_validate is called after reading $form_state[input] and date_combo_validate_date_start is called after validating the date.

The only solution I could come up with was to overwrite the values in both $form_state['values'] and $form_state['input'] from my widget validation.

I could have tried working on a patch but at this point, I am not sure if there is a specific reason to use $form_state['input']. All the documentation I have looked at suggests not to use it unless needed and I am not sure of the need here.

KarenS’s picture

Status: Active » Closed (fixed)

The original issue is that there is a problem with default values. The re-opening is a question about why 'input' is used, a different issue and probably really a support request. The input values are used only in validation to identify which input value is invalid.

Re-closed because the original issue was already fixed.

jlscott’s picture

If you are here becuase of problem with enetered values not being present in $form_state['values'], then refer to my heads up at https://drupal.org/comment/8285811#comment-8285811. My experience indicated that spaces in the form element names causes this problem.