4

I am using the Field Collection module because I have some complicated relation between the fields, and I have tried to integrate it with the Unique field module, without success, because Unique field module is not supported by the Field Collection module.

Is there a simpler method to check if the value is unique, and the to display validation error, if the value is not unique?

Unfortunately, Drupal 7 has not this feature by default, so there must be a method to do this.

  • I wasn't aware field collection had limitations on what types could be attached. Can you describe what happened when you tried to attach a unique_field to a collection? Also, what is your criteria for uniqueness in this case? A unique entity-id for the collection? A unique combination of values (analogous to a compound key in a database)? Or a unique value in one of the collections' fields? – Dylan Tack Aug 30 '11 at 7:41
  • The criteria for uniqueness is the value in the filed. Actually is a string which act as a serial number. – Ek Kosmos Aug 31 '11 at 5:57
  • I found a way to verify if the value of a field is unique, but it's usable only if the field contains a reference to an entity. I don't think you are interested to such limited case. – kiamlaluno Aug 31 '11 at 23:36
  • 3
    If the two modules are incompatible, that's a bug. There has been nothing filed in the Field Collection queue, have you filed an issue with Unique Field? – tim.plunkett Aug 31 '11 at 23:39
  • I would post this as an answer, but I am not terribly familiar with this aspect of the D7 API yet. Can a query and uniqueness check just be done in a hook_node_validate()? – mpdonadio Sep 1 '11 at 0:25
8
+50

You need to implement this in a custom module, here is a sample code to achieve this:

function custom_node_validate($node, $form) {
  if ($node->type == 'page') {
    //retrieve the value for your field using Entity API
    $wrapper = entity_metadata_wrapper('node', $node);
    $value = $wrapper->field_collection->field_unique->value();

    //Execute a count query to see if there's other similar values.
    $query = new EntityFieldQuery;
    $query->entityCondition('entity_type', 'field_collection_item')
      ->fieldCondition('field_unique', 'value', $value)
      ->count();
    $count = $query->execute();
    if ($count > 1) {
      form_set_error('field_unique', 'Unique field value is already used.');
    }
  }
}

A few disclaimers:

  • I am really stocked by the complexity of Field Field Collection API and it was pretty complicated to find good information about how to retrieve values and make queries.
  • I really enjoy doing SQL queries (see How to change the legnth of field settings) but I tried to only use the API instead of doing a simple query on the table field_data_field_unique. However it may not yet be perfect so please feel free to chime in.
  • The form_set_error() isn't highliting the field, I was unable to find the correct name.

Here are the documentation I used:

Edit: Following chx advice, to pass directly field_name to fieldCondition().

  • 1
    It boggles my mind why on earth would you need entity API for this. Why are you not doing simple $items = field_get_items('node', $node, 'field_unique'); $value = $items[0]; ? Next up, there is no need to run field_info_field() you can happily pass a field_name to fieldCondition. Finally, I think the name of the field would be field_unique[LANGUAGE_NONE] – user49 Sep 4 '11 at 1:30
  • 1
    The problem here is Field Collection, field_unique is attached to field_collection so field_get_items can't retrieve it directly. I feel the same, this look way over engineered but I couldn't find a better API. Regarding the field_unique[LANGUAGE_NONE] it doesn't work as field collection gets in the middle. Thanks for your tips :) – tostinni Sep 4 '11 at 10:28
4

I haven't programmed a module yet but it sounds like it might be easier to write a hook on form_alter and then query against your existing "serial number" field to make sure it's unique.

  • 1
    Yes, this could be a good idea I think. – Ek Kosmos Sep 2 '11 at 20:15
1

Basically Ek Kosmos has the basic idea. The easiest would be to create a small custom module, this has the advantage of isolating the feature you want to build, and remember the #1 rule, you really never want to hack anything in core, unless you really cannot avoid it.

Once you have your .info file setup in a folder and .module file ready to go as indicated in the many how-to's on the subject, you leverage the power of hook_form_alter by writing a function named your-module-name _form_alter in your module file and you know that function will be called.

You would probably need a switch statement dependent in the form)alter to perform specific actions depending on the form id,

You would probably need to try adding an attribute (#validate) that adds a function call on the form array, being a function name of your own custom validation function.

Something like:

   // #validate adds callback to custom validator.
   $validators = $form['#validate'][]; // Save existing validation calls. 
   //  Not clear in docs, but this is important!

  // In your case, you may want to add a method callback with this attribute.                                   
  $form['#validate'][] = $validators . ' _custom_validate';

Of course, in your validation function you could log errors, redirect, assign error messages or notifications.

Do read the form api and download the form examples.

If you need help and examples galore, download contrib modules and see how others tackeled the beast, or post questions here as you go along.

Happy conding, good-luck.

1

Finally here is how I did adapting and tacking suggestions form @tostinni, @stefgosselin, @uwe999 answers and others:

/**
 * implementation of hook_form_alter().
 */
function CUSTOM_MODULE_form_alter(&$form, &$form_state, $form_id) {
    switch ($form_id) {
        case 'MY_FORM_ID':
            // add custom validation callback
            $form['#validate'][] = 'CUSTOM_MODULE_MY_FORM_ID_validate';
            break;
            ...
        default:
            break;
    }
}

then all the functionality I implemented in:

/**
 * implementation of hook_form_FORM_ID_alter
 */
function CUSTOM_MODULE_MY_FORM_ID_validate(&$form, &$form_state) {

    //retrieve the value for your field
    $value = $form_state['values']['field_MY_FIELD']['und'][0]['value'];

    //Execute a count query to see if there's other similar values.
    $query = new EntityFieldQuery;
    $query->entityCondition('entity_type', 'field_collection_item')
            ->fieldCondition('field_MY_FIELD', 'value', $value)
            ->count();
    $count = $query->execute();
    if ($count > 0) {
        form_set_error('field_MY_FIELD', 'Unique field value is already used.');
    }
}

I have tried to work with entity_metadata_wrapper but unfortunately I have not succeed.

Thank you for your answers.

1

Try with field validation module, use unique validator. Add a validation rule, choose unique scope, global, entity,bundle.

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.