From The Blog

Drupal: Form Validation Messages Order

27 July 2017, in DrupalPHP

Hello all Drupalists,

Have you ever had a problem with form validation messages order, ... I think we all had this issue.

For some reason validation messages are not ordered the right way (with the same order as the form fields).

For this reason, I wrote the below code to be used to reorder form validation messages.

Note that the below code also has a function to be used if you are using conditional fields module to manage field dependencies.

 

/**
 * Reorder form validation messages using field weights
 * @param  Array $form Form array
 * @return void
 */
function _MY_MODULE_order_form_validation_messages_by_field_weights($form, $form_state){

  // Use the following function only if you use conditional fields module to manage dependencies
  _MY_MODULE_form_conditional_fields_handle_validation_messages_dependencies($form, $form_state);

  // $field_order = array();
  $form_fields = array();

  foreach($form as $element_name => $element){
    if(is_array($element) && isset($element['#weight'])){
      $form_fields[$element['#weight']] = $element_name;
      // This is not accurate as it is ordinary for two fields to have the same weight :-S
      /*$field_order[$element['#weight']][] = $element_name;
      if(isset($element['#language']))
        $field_order[$element['#weight']][] = $element_name.']['.$element['#language'];*/
    }
  }

  ksort($form_fields);

  $error_messages = form_get_errors(); // Get form validation error messages
  $messages = drupal_get_messages('error', TRUE); // Get error messages
  form_clear_error(); // Clear form validation errors
  
  foreach($form_fields as $weight => $field_name){
    foreach($error_messages as $index => $message){
      if(strpos($index.']', $field_name) !== FALSE){
        // drupal_set_message($error_messages[$index], 'error', FALSE);
        form_set_error($field_name,$error_messages[$index]);
        unset($error_messages[$index]);
      }
    }
  }
}



/**
 * Manage fields with dependencies which are managed by conditional fields module
 * Use this function only if you are using conditional fields module to manage field dependencies
 */
function _MY_MODULE_form_conditional_fields_handle_validation_messages_dependencies($form, $form_state){
  /*************** From Conditional fields module **************/
  if (empty($form_state['conditional_fields_untriggered_dependents'])) {
    return;
  }

  $untriggered_dependents_errors = array();

  foreach ($form_state['conditional_fields_untriggered_dependents'] as $field) {
    $dependent = drupal_array_get_nested_value($form, $field['parents']);
    $field_values_location = conditional_fields_form_field_get_values($dependent, $form_state);

    // If we couldn't find a location for the field's submitted values, let the
    // validation errors pass through to avoid security holes.
    if (!isset($field_values_location[$dependent['#field_name']])) {
      if (!empty($field['errors'])) {
        $untriggered_dependents_errors = array_merge($untriggered_dependents_errors, $field['errors']);
      }
      continue;
    }

    if (empty($field['reset'])) {
      unset($field_values_location[$dependent['#field_name']]);
    }
    else {
      $dependent_info = field_form_get_state($dependent['#field_parents'], $dependent['#field_name'], $dependent['#language'], $form_state);
      $field_values_location[$dependent['#field_name']][$dependent['#language']] = field_get_default_value($dependent_info['instance']['entity_type'], NULL, $dependent_info['field'], $dependent_info['instance'], $dependent['#language']);
    }

    // Save the changed array back in place.
    // Do not use form_set_value() since it assumes that the values are located at
    // $form_state['values'][ ... $element['#parents'] ... ], while the
    // documentation of hook_field_widget_form() states that field values are
    // $form_state['values'][ ... $element['#field_parents'] ... ].
    drupal_array_set_nested_value($form_state['values'], $dependent['#field_parents'], $field_values_location);

    if (!empty($field['errors'])) {
      $untriggered_dependents_errors = array_merge($untriggered_dependents_errors, $field['errors']);
    }
  }

  if (!empty($untriggered_dependents_errors)) {
    // Since Drupal provides no clean way to selectively remove error messages,
    // we have to store all current form errors and error messages, clear them,
    // filter out from our stored values the errors originating from untriggered
    // dependent fields, and then reinstate remaining errors and messages.
    $errors = array_diff_assoc((array) form_get_errors(), $untriggered_dependents_errors);
    form_clear_error();
    $error_messages = drupal_get_messages('error');
    $removed_messages = array_values($untriggered_dependents_errors);

    // Reinstate remaining errors.
    foreach ($errors as $name => $error) {
      form_set_error($name, $error);
      // form_set_error() calls drupal_set_message(), so we have to filter out
      // these from the messages to avoid duplicates.
      $removed_messages[] = $error;
    }

    // Reinstate remaining error messages (which, at this point, are messages that
    // were originated outside of the validation process).
    foreach (array_diff($error_messages['error'], $removed_messages) as $message) {
      drupal_set_message($message, 'error');
    }
  }
}

 



Post a Comment