You are here

function conditional_fields_form_validate in Conditional Fields 7.3

Validation callback for any form with conditional fields.

This validation callback is added to all forms that contain fields with dependencies. It removes all validation errors from dependent fields whose dependencies are not triggered, which were collected at field-level validation in conditional_fields_dependent_validate().

See also

conditional_fields_dependent_validate()

1 string reference to 'conditional_fields_form_validate'
conditional_fields_form_after_build in ./conditional_fields.module
after_build callback for forms with dependencies.

File

./conditional_fields.module, line 739
Define dependencies between fields based on their states and values.

Code

function conditional_fields_form_validate($form, &$form_state) {
  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_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');
    }
  }
}