I really like the Workflow Required Fields module, but I have one problem with it: It does not show the user which fields are required until after they've submitted the form. That is not user-friendly in my book. So I tried to come up with a solution. What I came up with works for me. I am a rank beginner at module development, so I'd appreciate any feedback on it, and I'd also be curious to know whether it, or something like it, could be a useful contribution to the module.

My first attempt at a solution was pretty crude: I changed line 55 in wf_required_fields to $sid = workflow_node_current_state($form['#node'])+1; That at least telegraphed the requiredness to the user, but it created other problems.

I've created an online application which the user can save and return to later. So the workflow states are Saved and Submitted. There are several required fields, but I want the user to be able to Save repeatedly without filling any or all of those in until it's time to Submit. On the other hand, I want them to know up front which fields will be required ultimately.

My first solution (above) broke when I tried to Save an application a second time, since it wanted to require all the required fields at that point. My next solution was to create a new function in wf_required_fields.inc, modify an existing function in wf_required_fields, and override the theme_form_element function.

The end result is that all the fields that are required to promote the application to the Submitted state are marked as such from the beginning, but the error messages don't kick in if the transition is Saved -> Saved.

In the case of a workflow with more than two states, some tweaking could show both the "Ultimately Required" and the "Required For Next Transition" status for each field.

In wf_required_fields.inc (note that this is closely modeled on the wf_required_fields_is_required function, except this checks to see if a field is EVER required) :

/**
 * Checks whether a certain field is configured to be required in a node of a
 * certain content type in ANY state.
 * 
 * @param string $type The content type to check
 * @param string $field The name of the field to check
 * @param int $sid The sid of the state to check
 * @return bool true: field is required; false otherwise
 */
function wf_mark_fields_as_required($type, $field) {
  $output = 0;
  $settings = variable_get( 'wf_required_fields', array() );
  $sids = $settings['settings'][$type]['table'][$field];
  foreach (array_keys($sids) as $sid) {
    if (! isset($settings['settings'][$type]['table'][$field][$sid]['required'])) {
      return false;
  	}
  	if ($settings['settings'][$type]['table'][$field][$sid]['required'] == '1') {
  	    $output++;
  	} 
  }  	
  return $output;
}

In wf_required_fields.module, I changed the wf_required_fields_form_alter function thus, so that it adds another constituent to the field array, #required_ult. (The last foreach is the new part; note that I have changed line 55 back to its original state.):

/**
 * Implementation of hook_form_alter().
 * 
 * Sets the '#required' property of configured fields in node edit forms. 
 * 
 * @param string $form_id The form id
 * @param array &$form Forms API array of the form
 * @todo Eliminate (or disable) fields that are required on the cck field
 *  configuration page
 */
function wf_required_fields_form_alter($form_id, &$form) {
  if ($form['#id'] !== 'node-form') {
    return; // wrong form
  }

  $node = $form['#node'];
  $type = $node->type;
  $types = wf_required_fields_get_types_configured();
  if (! isset($types[$type])) {
    return; // node type is not configured to be handled by this module
  }

  $sid = workflow_node_current_state($form['#node']); 
  $info = content_types($type); //
  $fields_available = $info['fields'];
  foreach (array_keys($fields_available) as $field) {
    if (wf_required_fields_is_required($type, $field, $sid)) {
      $array = &wf_required_fields_find_required($form, $field);
      if ($array !== null) {
        $array['#required'] = true;
      }
    }
  }
  
  foreach (array_keys($fields_available) as $field) {
    if (wf_mark_fields_as_required($type, $field)) {
      $array = &wf_required_fields_find_required($form, $field);
      if ($array !== null) {
        $array['#required_ult'] = true;
      }
    }
  }
  
}

Lastly, I overrode the theme_form_element function with this (only the line beginning with "$required" was changed):

/**
 * Return a themed form element.
 *
 * @param element
 *   An associative array containing the properties of the element.
 *   Properties used: title, description, id, required
 * @param $value
 *   The form element's data.
 * @return
 *   A string representing the form element.
 */
function phptemplate_form_element($element, $value) {
  $settings = variable_get( 'wf_required_fields', array() );
  $sids = $settings['settings']['mcnair_application']['table'][$field];
  $output  = '<div class="form-item">'."\n";
  $required = !empty($element['#required_ult']) ? '<span class="form-required" title="'. t('This field is required.') .'">*</span>' : '';
  
  if (!empty($element['#title'])) {
    $title = $element['#title'];
    if (!empty($element['#id'])) {
      $output .= ' <label for="'. $element['#id'] .'">'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
    else {
      $output .= ' <label>'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
  }

  $output .= " $value\n";

  if (!empty($element['#description'])) {
    $output .= ' <div class="description">'. $element['#description'] ."</div>\n";
  }

  $output .= "</div>\n";

  return $output;
}

Comments

traxer’s picture

Status: Active » Closed (won't fix)

On the other hand, I want them to know up front which fields will be required ultimately.

The workflow module does not support the notion of an "ultimate state". In my custom modules I use (by convention) the state with the highest weight. I do not want to enforce this convention in my published modules.

Checks whether a certain field is configured to be required in a node of a certain content type in ANY state.

I did indeed write the module because nodes where filled with content as they mature. But it is also possible that a field such as "todo" should be required in the "draft" state, while it should not be required in the later "tendered", "reviewed" and "published" states.

Lastly, I overrode the theme_form_element function ...

That function is the responsibility of the forms system. It would be a bad move of the drupal core team to change it for the sake of my module. I cannot rely on a certain implementation of phptemplate_form_element either.

I am, however, planning to tell the user beforehand, what is missing for each allowed transition to succeed. The logic should be fairly simple. I'm not yet sure whether to use drupal_set_message or to add a sentence to $element['#description']. I opened a new issue for that: #207465.

Thank you for your comment.

adshill’s picture

We're looking for something similar to this, however due to the way the module works I think I need something a bit simpler - rather than looking at what is "Ultimately" required, just looking at the next workflow state, and adding a red asterisk (*) to those items (but not using the drupal validation/required code):

I need a patch that basically add the required field (*) to the fields that are required in the next workflow state, however it should NOT validate those fields. The point being that the module does the validation itself and therefore its not possible to use the internal drupal validation, but I need users to see which fields this module is requesting when trying to move to the next state.

I kinda got it working using some of the code in that post - I got the red (*) to appear on the items of the next workflow state quite easily, the problem was that then drupal tried to validate them, which didn't allow me to save in the current state.