7

What is the best way(hook) to validate all instances of a field programmatically? I have a lot of content types having the same fields like field_phone. I want to programmatically validate field_phone everywhere it is used.

7
  • 1
    Is this a one-time evaluation or something you always want to be applied? If it's something to always apply, you can simply add the field validation normally and then re-save all the nodes with that field... Aug 17, 2013 at 14:51
  • @PatrickKenny I want to write a module for it.
    – hpn
    Aug 18, 2013 at 2:15
  • 1
    But a module to one-time revalidate all your data or a module to validate it everywhere on each submit?
    – Mołot
    Aug 19, 2013 at 14:06
  • Specify the validate function while form field generating.
    – deem
    Aug 19, 2013 at 14:09
  • @Mołot a module to validate it everywhere on each submit
    – hpn
    Aug 19, 2013 at 14:09

5 Answers 5

6

You could implement hook_field_validate and check if its the correct instance. Doesnt work if the field is not defined by the module.

One way to build that would use hook_form_alter and add element_validator if the field exists on the form.

function mymodule_form_alter(&$form, &$form_state, $form_id) {
   if (isset($form['field_phone'])) {
      $form['field_phone']['#element_validate'][] = 'mymodule_somevalidator';
    }
 }

function mymodule_somevalidator($element, &$form_state) {
  if (!empty($element['#value']) && !is_numeric(parse_size($element['#value'])) {
    form_error($element, t('The "!name" must be x', array('!name' => t($element['title']))));
  }
} 
3
  • 1
    hook_field_validate won't work. It is a hook to be implemented by modules defining fiend types. You may want instead to implement hook_field_attach_validate.
    – jonhattan
    Aug 22, 2013 at 9:36
  • @jonhattan: Edited the answer. You are right, most likely field is not defined by the module.
    – user20301
    Aug 22, 2013 at 10:39
  • This worked for me with a minor modification: Instead of $element['#value'], I had to use $element[$element['#language']][0]['#value'] and Instead of $element['title'], I had to use $element[$element['#language']][0]['#title']. Hope this helps. Oct 16, 2017 at 6:00
4
+100

Try the Field Validation module.

You still have to add proper validation to each field you want to validate.

2

From field_attach_form_validate:

There are two levels of validation for fields in forms: widget validation, and field validation.

for widget validation you may follow the hook_form_alter path. This is hard to generalize since you need to know details about how the form is built. For example elements or values may be nested for some entities.

IMO, it's best to do field validation. It is performed by implementing hook_field_attach_validate. Here's a simple example:

function hook_field_attach_validate($entity_type, $entity, &$errors) {
  if (isset($entity->field_phone)) {
    $errors['field_phone'][LANGUAGE_NONE][0][] = array(
      'error' => 'error_key',
      'message' => t('Error message'),
    );
  }
}

error_key is used by hook_field_widget_error to flag a form element when a widget is compound of several elements. For example, in text field's implementation of this hook the error key text_summary_max_length is used to flag an element within the widget structure.

In the general term, the error key is not used for widgets with a single element. In the case of phone field type (that I assume you're using), they provide a compound widget but don't implement error distribution to elements, so just ignore it.

1

The best way to implement it by implementing hook_form_alter. The logic is such that you need add the custom validation function against all those Content Type forms which have the same field like field_phone (in your case) and it needs to be dynamic. Once, I had encountered such situation but I had to validate against the single form. The code below is almost the same implementation but I have made it much more dynamic for your case.

Create a module and implement hook_form_alter like this:

/**
 * Implementation of hook_form_alter
 */
function MODULE_NAME_form_alter(&$form, $form_state, $form_id) {
  // $cck_type contains the array of all Drupal content type machine names
  $cck_type = array_keys(node_type_get_types());

  // Machine names of those content type whose instance you want to validate
  // Add your machine name for whom you want to validate. You can get the 
  // machine names of content types from Admin > Structure > Content types. Fill
  // as many required bu you.
  $my_types = array('CCK_TYPE_1', 'CCK_TYPE_2', 'CCK_TYPE_3');

  // Since, a user fill one form at particular time. The variable $current_type 
  // hold the Content Type machine name for current form. 
  if (arg(0) == 'node' && arg(1) == 'add') {
    $current_type = arg(2);
  } elseif ((arg(0) == 'node') && is_numeric(arg(1)) && (arg(2) == 'edit')) {
    $node = node_load(arg(1));
    $current_type = $node->type;
  }

  // gets current form's ID
  $id_of_form = $form['form_id']['#value'];

  // checks if the current form is part of Drupal Content Type
  if (in_array($current_type, $my_types) && in_array($current_type, $cck_type)) {
    $id_of_form = $form['form_id']['#value'];
    if ($form_id == $id_of_form) {
      // Adding custom validation function to the form so that we can validate
      // the field of that form
      $form['#validate'][] = 'custom_validates';
    }
  }
}

Now, implement the custom validation function for validation.

/**
 * Implementation of custom validation for validating 'field_phone' in your case.
 * It can be any field, assuming that it is part of that form.
 */
function custom_validates(&$form, $form_state) {
  $values = $form_state['values'];

  // Language of the $form
  $lang = $form['language']['#value'];
  $field_phone = $values['field_phone'][$lang][0]['value'];

  // In my case, for testing purpose, I had set the strings in Phone field
  if (!is_integer($field_phone)) {
    form_set_error('field_phone', 'Invalid phone number');
  }
}

In the simple approach, you just need to check the $form_id of your content type form and add the custom validation function like this:

/**
 * Implementation of hook_form_alter
 */
function MODULE_NAME_form_alter(&$form, $form_state, $form_id) {
  if (($form_id == 'content_type_form_id_1') ||
          ($form_id == 'content_type_form_id_2') ||
          ($form_id == 'content_type_form_id_3')) {
    // Adding custom validation function to the form so that we can validate
    // the field of that form
    $form['#validate'][] = 'custom_validates';
  }
}

But the problem with this simple approach is such that you will need to know form ID of every single content type form and then add it to the if statement with || operator as I have shown previously. This will take a lot of your time.

I have made respective comments to make your understand the logic and implementation.

I hope that my solution answers your problem.

0

The answer is hook_field_widget_WIDGET_TYPE_form_alter() in my opinion. Use the hook to add your validation callback to the $element[#element_validate] array and you are good to go.

hook_form_alter() is very general and it will be invoked for every form whether it has field_phone or not (increasing overhead). Besides, what if the field_phone is deep inside various field sets or containers? You will have to look for it recursively (additional overhead).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.