After I've processed a field collection migration for the first time, on subsequent updates of that migration I never get updated information, it's always the old information, I think due to the following, starting at line 123 of field_collection.migrate.inc:

    // Restore fields from original field_collection_item if updating
    if ($updating) {
      foreach ($entity as $field => $value) {
        if ('field_' != substr($field, 0, 6)) {
          continue;
        }
        elseif (property_exists($entity_old, $field) && !property_exists($collection, $field)) {
          $entity->$field = $entity_old->$field;
        }
      }
    }

Basically, before this code block, it clones the old field collection item, and then before saving the entity it runs this block of code, which will restore all fields to what they were in the original field collection item. This literally makes no sense. Why is this here?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

lpeabody created an issue. See original summary.

lpeabody’s picture

Status: Active » Needs review
FileSize
888 bytes
lpeabody’s picture

Assigned: lpeabody » Unassigned

So, after digging deeper into Migrate and comparing the way other modules handle destination migrations, I came away with the following knowledge. If you are changing fields on entities, but those fields aren't tracked in a field mapping (i.e. no field mapping specified for the fields but you are modifying the fields in the migration's prepare method), then the field will always be reverted to the value it had before running the migration with the update flag. This happens because the prepare method is invoked prior to restoring the old field data in the destination handler.

Now, to me, it probably makes sense to have the prepare method come after data is restored to the entity about to be saved (in this case a field collection). This is because the wording in the documentation around the prepare method implies this. You get to make final adjustments to the entity prior to being saved. If magical things are happening to it after you've changed them in the prepare method, this can really cause confusion, like it did in my case.

All this being said, I feel like it makes sense to have the prepare method come after the code block which restores old field data. Either that, or update the documentation surrounding the prepare method as well as the documentation for the repercussions of not adding fields via addFieldMapping.

Workaround:
It's not really a workaround because I'm using it as was intended, but it wasn't straight forward getting to this point.
I had 5 fields that I was modifying in the prepare method, but I did not track these fields via addFieldMapping. Therefore, after I initially created the data, on subsequent updates these field values would be reverted back to the original data that was provided during the first migration.

My workaround was to add these fields to the migration via addFieldMapping, and providing dummy default values. I then processed the data in the prepare method as I was previously doing.

TL;DR: If you run into this situation, just add the offending fields via addFieldMapping and provide a defaultValue, even if that defaultValue will never get used.

lpeabody’s picture

Status: Needs review » Active