It would be great to see a rule that would allow you to specify a value that a summed set of number fields should be equal to.

Use case:

There is a set of number fields used to report percentage of time spent on various subject areas.

Research Time Spent:

  • Area 1
  • Area 2
  • Area 3
  • Area 4

You would then setup a validation rule specifying that those 4 fields' values should be equal to 100.

Comments

chertzog’s picture

I needed this for a project, wasnt to hard to write.

/**
 * Implementation of hook_webform_validation_validators().
 */
function mymodule_webform_validation_validators() {
  return array(
    'sum' => array(
      'name' => "Sum to Specified number",
      'description' => 'Make sure that values sum to the specified number.',
      'custom_data' => array(
        'label' => t('The number the specified fields should sum to'),
        'description' => t('Specify the number the fields should sum to in order to pass validation.'),
      ),
      'component_types' => array(
        'number',
      ),
    )
  );
}

/**
 * Implementation of hook_webform_validation_validate().
 */
function mymodule_webform_validation_validate($validator_name, $items, $components, $rule) {
  if ($items) {
    switch ($validator_name) {
      case 'sum':
        foreach ($items as $key => $val) {
          $values[] = $val;
        }
        $sum = array_sum($values);
        if($sum > $rule['data'] || $sum < $rule['data']){
          foreach ($items as $key => $val) {
            $errors[$key] = t('Please adjust values so they sum to %number', array('%number' => $rule['data']));
          }
          return $errors;
        }
        break;
    }
  }
}
steve_lou’s picture

It works for me,but by the way ,can I set one of the items equals the sum of the others items? such as Area 4=Area 1+Area 2+Area 3
I need $rule['data'] to be the value of Area4.
thank you very much, chertzog .

chertzog’s picture

What you could do is change the "custom_data" parameters to accept the "field_key" of "Area 4". Then use that form key to find the value of the "Area 4" and do your comparisons that way.

liam morland’s picture

Version: 7.x-1.1 » 7.x-1.x-dev

Please provide the code as a patch to the latest development version for inclusion.

Rubinja’s picture

Issue summary: View changes

Can anyone help me out on how to use this code?

Where do I need to copy/paste it?

Thanks in advance!

Ruben

liam morland’s picture

The code would need to go in a custom module. In the example above, the name of the custom module is "mymodule".

  • Liam Morland committed 93bdc3c on 7.x-1.x
    Issue #1545980: Validate sum of number components: >, >=, =, <=, <.
    
  • Liam Morland committed e85e380 on 7.x-1.x
    Issue #1545980: Refactor: Create and use...
liam morland’s picture

Status: Active » Fixed

Status: Fixed » Closed (fixed)

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

TheWrench’s picture

Thank you for this amazing custom module, chertzog. Did exactly what I needed it to!

jbova’s picture

In reply to steve_lou, and credit to the idea from chertzhog, here is a working example:

function mymodule_webform_validation_validators() {
  $validators = array(
    'sum_vs_other' => array(
      'name' => t('Sum to Value of Specified Field'),
      'component_types' => array(
        'number',
      ),
      'custom_data' => array(
        'label' => t('The chosen fields should sum to the value of the following key'),
        'description' => t('Specify the field key containing the number the fields should sum to in order to pass validation.'),
      ),
      'description' => t('Make sure that values sum to the value of the specified field.'),
    )
  );
  return $validators;
}

/**
 * Implementation of hook_webform_validation_validate().
 */
function mymodule_webform_validation_validate($validator_name, $items, $components, $rule) {
  if ($items) {
    switch ($validator_name) {
      case 'sum_vs_other':
        foreach ($components as $key => $val) {  
          if ($val['form_key'] == $rule['data']) {
            $matchme_key = $key;
            $matchme_val = $items[$key];
            $matchme_name = $components[$key]['name'];
            break;
          }
        }
        if ($matchme_key) {
          foreach ($items as $key => $val) {
            if ($key != $matchme_key) {
              $values[] = $val;
            }
          }
          $sum = array_sum($values);
          if($sum > $matchme_val || $sum < $matchme_val){
            foreach ($items as $key => $val) {
              $errors[$key] = t('Please adjust the values of this row so they match the value of %matchme_name (%matchme_val)', array('%matchme_name' => $matchme_name, '%matchme_val' => $matchme_val));
            }
            return $errors;
          }
          break;
        }
    }
  }
}

For this example, you would need to select all fields which should be summed AND the field you are comparing against when setting up the validation rule. For the custom data, you enter the field key. This field is excluded from the sum, and then compared to the sum of the other fields.