In salesforce_mapping_property_fieldmap_pull_value(), $value often (but not always) ends up as an empty string even when the source value is null. This has the effect of sort of deleting the existing value in Drupal if it exists. If it is null, the value doesn't get removed in Drupal. With it set to an empty string, it is saved as an empty string, resulting in getting displayed as a field label with only an empty string for a value.

What would be preferable is to fully delete the field value, instead of setting it to an empty string. If it's null at salesforce, it's safe to assume it should be removed in Drupal.

Solution would probably deal with looking at the node data build and node save operations. Something like: if field is mapped and sf field value is null, remove existing drupal values.

Comments

nadavoid’s picture

Issue summary: View changes
nadavoid’s picture

Category: Feature request » Bug report

Found the pattern of nulls vs empty strings. Any Drupal data type that is not explicitly handled in salesforce_mapping_property_fieldmap_pull_value() ends up being null, if it comes from Salesforce as null. The data types currently handled are list (multi-value select fields), date, boolean, and text. That leaves all other types unhandled, including uri, integer, and decimal. This has the effect of those types not getting deleted from Drupal when they are deleted in Salesforce.

nadavoid’s picture

Status: Active » Needs review
StatusFileSize
new2.1 KB

Attached patch should resolve the issue. In my testing, values are properly deleted when pulled from salesforce, with this patch. Tested with simple fields as well as picklists/arrays.

nadavoid’s picture

Status: Needs review » Needs work

There are likely still problems with #4. I haven't tested with related entities, which is probably the reason for having that $parent variable which points to a field wrapper.

merilainen’s picture

At least the patch is a step forward, now empty decimal fields are emptied correctly in Drupal. Perhaps related entities could be handled in a separate issue? Probably a lot less popular use case.

tauno’s picture

StatusFileSize
new996 bytes

Here's another approach - the idea is to not push empty values in the first place. This may not properly delete existing values yet, but it's a similar issue. Needs much more testing and work.

tauno’s picture

StatusFileSize
new3.49 KB

Some additional work to attempt to delete field values as well as only triggering saves when at least one field value has changed.

nrackleff’s picture

Have not tried the patch yet, but in response to #3. The experience I am having on text fields is when they are deleted in SF and come down as null in the SF object, they do not get adjusted at all. Not set to empty string or to null. They just remain as is, not changed at all. So for me, text fields deleted in SalesForce are not getting deleted in Drupal. Will try the patch ASAP.

pianomansam’s picture

Patch in #4 mostly worked for me, but it resulted in some address fields loosing data.

pianomansam’s picture

Status: Needs work » Needs review

After more tests, I've confirmed that #8 is working for me. Patch #4 should NOT be used as it results in data loss. Basically, #4 assumes that if the mapped property is empty, the entire field should become blank. This is a problem, though, because the mapped property might be an optional property. And if it's optional we don't want to make the whole field empty.

aaronbauman’s picture

Status: Needs review » Needs work

This has a minor potential side-effect of nullifying "0" (zero) or "FALSE" values.
Need to ensure that this truly only applies to NULL.

nielsonm’s picture

Status: Needs work » Needs review
StatusFileSize
new4.67 KB

Re-rolling for latest dev.

mariacha1’s picture

Status: Needs review » Needs work

I agree with aaronbauman on this one: The latest patch has the side effect of clearing out any fields with any values that come down from Salesforce as FALSE or 0 or empty arrays due to the nature of empty(). I'm not sure this would always be desired.

Here's a list of test cases with what I assume is the desired result vs the current results. Current Outcome (with patch #13), if they are not the Desired Outcome, are in italics:

Case 1:
Drupal Field: No value (empty)
Salesforce Field: No value (empty)
Desired Outcome: Nothing happens

Case 2:
Drupal Field: Set as 0
Salesforce Field: No value (empty)
Desired Outcome: Drupal field value is deleted

Case 3:
Drupal Field: No value (empty)
Salesforce Field: Set as 0
Desired Outcome: Drupal field is set to 0
Current Outcome: Drupal field value is deleted

Case 4:
Drupal Field: No value (empty)
Salesforce Field: Set as FALSE
Desired Outcome: Drupal field is set to FALSE
Current Outcome: Drupal field value is deleted

Case 5:
Drupal Field: No value (empty)
Salesforce Field: Set as "" (empty string)
Desired Outcome: Drupal field is set to "" (empty string)
Current Outcome: Drupal field value is deleted

Case 6:
Drupal Field: Set as any value (1 let's say)
Salesforce Field: No value (empty)
Desired Outcome: Drupal field value is deleted

If I'm wrong about the desired outcome on any of these, I'm open to hear arguments. Otherwise, we need to think a bit more about the use of empty() in the included patch.

chrisolof’s picture

Status: Needs work » Needs review
StatusFileSize
new5.68 KB

I believe the attached patch satisfies mariacha1's test cases, but needs community testing and feedback.

The approach is to essentially let NULL flow through to the field set operation and only process/alter/Drupalize the value if there is, in fact, a value provided from SF.

nielsonm’s picture

@chrisolof -

Thanks for picking this up. However it looks like the if statement in the mapping skips over Case 6: field value deletion. I'm going to see if I can take care of that particular edge case since deleting a value in SalesForce, then doing a pull results in an exception. Let me know if you have any thoughts on the issue.

Mike

chrisolof’s picture

@nielsonm We've got the patch in #15 running on a production site and case 6 is working reliably for us.

If you're getting an exception on Pull after applying this patch, it's been my experience that you probably have a required field in Drupal mapped to an optional field (or occasionally empty field) in SF. When you pull empty (NULL) into a required Drupal field you'll get an exception.

Quick fix is to make the field optional on Drupal.

If that's not possible you may want to look into utilizing hook_salesforce_pull_entity_value_alter() to convert empty (NULL) values coming from the Salesforce field into some sort of default value that can then be stored into the required Drupal field.

If you're curious as to why this happens - the guts of the SF module utilize entity metadata wrappers to set field data. Entity metadata wrappers throw an exception when you attempt to empty a required field on an entity.

vaish’s picture

Patch in #15 works great. We are using it in production for last 3 months without any issues. However, now that we introduced multi-select picklist in Salesforce, I noticed that clearing of all values in Drupal is broken - only first selected value gets cleared on each pull.

How to reproduce:

  • Create multi-select picklist in SF and map it to Drupal's multi value select list
  • Select all values in SF and save
  • After SF Pull, Drupal field will have all values selected as well
  • Now unselect all values in SF and save
  • After SF Pull, Drupal field will still have all values selected
  • Save SF record again to trigger SF Pull
  • After SF Pull, Drupal field will have first value unselected, all others will remain selected
  • Save SF record again to trigger SF Pull
  • After SF Pull, Drupal field will have first and second value unselected, all others will remain selected
  • etc...

Attached patch ensures empty value (NULL) received from Salesforce if muti-select picklist is emptied is handled correctly and empties select list on Drupal side.

I left code for handling case where value returned by SF is not array, although in my testing I couldn't reproduce such situation. If only single value is selected in SF, explode() in salesforce_mapping_property_fieldmap_pull_value() will still convert this value in array with one element.

olivier.bouwman’s picture

StatusFileSize
new5.87 KB

I was getting the following error when clearing a url field in Salesforce and syncing to Drupal: "Invalid data value given. Be sure it matches the required data type and format."

The reason is that when a field with multiple properties (like a link field) has a property that is required (url in the link field example) we cannot set the property/child value to null. We can however set the parent to null since it is not required. In case a field linked to a property gets cleared in Salesforce we assume it's fine to clear the parent of the property in Drupal.

This patch based on #18 should solve this. Many thanks to @gcb for his help with this patch.
There are a lot of changes in the patch, most is coding style, this is the actual change.

if (empty($value) && count($drupal_fields_array) > 1
    && empty($child_wrapper->info()['parent']->info()['required'])
    && !empty($child_wrapper->info()['required'])) {
  $child_wrapper->info()['parent']->set($value);
}
else {
  $parent->set($value);
}

  • gcb committed 2024b7b on 7.x-3.x authored by olivier.bouwman
    Issue #2199951 by tauno, vaish, nadavoid, nielsonm, chrisolof, olivier....

mariacha1 credited gcb.

mariacha1’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

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