1

I am using SalesForce suite to pull data from SalesForce to Drupal.

In the SalesForce object I have multiple date fields. These fields needs to map to a field-collection in the node. The field-collection can have multiple (unlimited) values.

So for example in the SalesForce object I have

sales_force_object -> start_date sales_force_object -> event_date sales_force_object -> end_date

which needs to map to

node -> the_dates [0] = sales_force_object -> start_date node -> the_dates [1] = sales_force_object -> event_date node -> the_dates [2] = sales_force_object -> end_date

The solution was to add 'temporary' fields on the node, let's call them:

node -> sync_start_date node -> sync_event_date node -> sync_end_date

When I get data from SalesForce (using pull; and yes the data comes through OK) - I map the values from the SalesForce object to the sync fields. Then just before the node is saved (updated), I use hook_node_presave to take values from the sync fields and create the field-collection items. This is the code:

  $fc = field_collection_item_load($key_dates_entity_id);
  $fc_wrapper = entity_metadata_wrapper('field_collection_item', $fc);
  $fc_wrapper->field_date->set((int) $date);
  $fc_wrapper->save();
  field_attach_update('node', $node);
  field_attach_presave('node', $node);
  entity_get_controller('node')->resetCache([$node->nid]);

You can safely assume that $key_dates_entity_id is the correct field-collection entity ID.

Inspecting the code I can see the entity is correctly updated (nothing wrong with the data), and when I check the MySQL general-log, I can see the data being saved to the database, however, when the set of instructions end, the old (cached) data is also saved. In other words the DB is updated twice - once with the new value, and once with the old values: net result is field collection items are not updated.

I have tried all sorts of combinations - nothing works. Any help please.

1 Answer 1

0

I would love to tell you why, but I have not been able to figure it out: I just know it works.

Initially I executed the code above in hook_node_presave($node), but obviously it did not work. So I figured I should try hook_node_update($node) - but that did not work either.

Then I discovered drupal_register_shutdown_function and now my hook_node_update looks like this:

function mymodule_node_update($node) {
  if ($node->type === 'node_type') {
    drupal_register_shutdown_function('_update_from_sync_fields', $node);
  }
}

node_type is the type of node I am checking against. Any case, once the node is actually saved - that is all processing is done, db transactions completed, etc - drupal will call my shutdown function. Now when I update the field values, and in specific field-collection fields - they are saved.

Of-course saving these fields and calling:

  field_attach_update('node', $node);
  field_attach_presave('node', $node);
  entity_get_controller('node')->resetCache([$node->nid]);

at the end of my shut-down function triggers hook_node_update again, but fortunately I have a token that tells me - so I do not execute the code again.

This solution works - what I am not happy about is the fact that it executes when Drupal is shutting down.

I think the problem is related to the fact that node_save starts a DB transaction, and when I update related entity (field-collection) items in hook_node_save or hook_node_presave I am starting another (nested) transaction. Clearly my transaction updating field-collection items completes, but when the outer (first) transaction then complete, it is writing old/dirty data.

The trick is going to be to clear the dirty data from cache. I was hoping entity_get_controller('node')->resetCache([$node->nid]); would do that - but clearly it does not?

So next I changed the hook_node_update to :

function mymodule_node_update($node) {
  if ($node->type === 'node_type') {
    _update_from_sync_fields ($node);
  }
}

in other words - from hook_node_update I simply call the 'shut-downfunction, then I rebuilt the drupal registry (drush rr`) and voila - it worked. Now I am even more confused. It is possible that my original code worked all along, but there was something wrong with the registry (or caches). All things being equal, all the examples I read was right.

From hook_node_update, load the field collection entity, update and save the entity. The clear the caches and do a field_attached_presave and field_attached_update like so:

  entity_get_controller('node')->resetCache([$node->nid]);
  field_attach_presave('node', $node);
  field_attach_update('node', $node);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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