I don't post nearly enough of these, but here's one of my various Drupal 6 "Application Tricks".

Setup:
- i have a node type which is used to add a "Resource". A resource can be either a web link (link field) or an uploaded document (file field).
- i have a tab on the Resource form which houses the Creative Commons licensing subform as well as various other fields which are related ONLY to an upload file. Some of these fields (checkbox signoffs, see screen: http://screencast.com/t/5FgD8NEVLtf0) are set in CCK as REQUIRED.

Task:
- i only want these required fields to validate if i am uploading a file (not if it is just a web link resource)

Solution:

NOTE: mymodule must have a high system weight such that other modules have run their validate scripts already

function mymodule_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == "resource_node_form") {
    $form['#validate'][] = '_mymodule_resource_file_upload_validate';
  }
}

function _mymodule_resource_file_upload_validate($form, &$form_state) {
  $upload = false;
  foreach ($form['#post']['field_file'] as $file) {
    if ($file['fid']) $upload = true;
  }
 
  // if we are uploading a file then we DO want our required fields
  // so just return and let Drupal do its thing
  if ($upload) return;
 
  // the required fields that we want to ignore since this isn't a file upload resource
  $safe_fields = array('field_agree', 'field_license_ack');
 
  // get a list of all errors
  $errors = form_get_errors();
 
  // clear all errors so we can add all of them back except the ones we are trying to clear
  form_set_error(null, null, true);
  if (count($errors)) {
    foreach ($errors as $field => $msg) {
      if (!in_array($field, $safe_fields)) form_set_error($field, $msg);
    }
  }
 
  // need to do similar thing with Error messages since they have already been set as well
  $messages = drupal_get_messages('error');     // this will clear Error msg queue
  if (count($messages)) {
    foreach ($messages['error'] as $msg) {
      if (stristr($msg, "Contributor's Agreement") || stristr($msg, "License Acknowledge")) continue;
      drupal_set_message($msg, 'error');
    }
  }
 
}

Peter Lindstrom
LiquidCMS - Content Solution Experts

Comments

ferrum’s picture

As form_set_error() also sets the error messages again, the easier version is:

function mymodule_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == "resource_node_form") {
    $form['#validate'][] = '_mymodule_resource_file_upload_validate';
  }
}

function _mymodule_resource_file_upload_validate($form, &$form_state) {
  $upload = false;
  foreach ($form['#post']['field_file'] as $file) {
    if ($file['fid']) $upload = true;
  }

  // if we are uploading a file then we DO want our required fields
  // so just return and let Drupal do its thing
  if ($upload) return;

  // the required fields that we want to ignore since this isn't a file upload resource
  $safe_fields = array('field_agree', 'field_license_ack');

  // get a list of all errors
  $errors = form_get_errors();

  $messages = drupal_get_messages('error');     // this will clear Error msg queue

  // clear all errors so we can add all of them back except the ones we are trying to clear
  form_set_error(null, null, true);
  if (count($errors)) {
    foreach ($errors as $field => $msg) {
      if (!in_array($field, $safe_fields)) form_set_error($field, $msg);
    }
  }
}

texas-bronius’s picture

The solutions above are Drupal 6. They were really close in Drupal 7, but form_set_error() didn't reset the error messages stack: I had inserted a drupal_set_message($key) in there just for debugging and had confirmed that it was executing as expected, and the fields did receive the Drupal FAPI field error css class, only the messages are not output to screen.

My use case: Have a radio selector Application Type of "single" or "joint" for credit application type, and when "single" is selected, I need to skip over field validation on the "Secondary Applicant" fields. Once I have that working, I am still a bit dubious how this might translate to toggling Application Type radios between form submissions, but first thing is first..

The difference was that I am working in Drupal 7. Read on!

Drupal 7 form_set_error() does away with Drupal 6 form_set_error()'s $reset flag, replacing it instead with $limit_validation_errors. That makes these awesome code snippets not work in D7. How to clear the form error stack now?

Drupal 7 introduces form_clear_error() to clear the FAPI form error stack instead of the now removed $reset third param to Drupal 6's form_set_error().

And so now both concerns mentioned earlier are gone by using the 2nd code snippet and replacing:

<?php
 
// clear all errors so we can add all of them back except the ones we are trying to clear
 
form_set_error(null, null, true);
?>

with

<?php
 
// clear all errors so we can add all of them back except the ones we are trying to clear
 
form_clear_error(); // New with Drupal 7
?>

--
http://drupaltees.com
80s themed Drupal T-Shirts

texas-bronius’s picture

Ah, I understand now why the @ferrum's shorter version works: when you clear both the form error and the messages error queues, our custom/intentional form_set_error within the foreach will be adding back any error notifications to the messages stack, making the drupal_set_message bit unnecessary/redundant. Kudos!

--
http://drupaltees.com
80s themed Drupal T-Shirts

WorldFallz’s picture

Also checkout the http://drupal.org/project/conditional_fields module -- works great.

_
Don't be a Help Vampire - read and abide the forum guidelines.
If you find my assistance useful, please pay it forward to your fellow drupalers.