I'm importing into a node type that can have FileField content, but not importing files (Migrate FileField support isn't even enabled). When I import into a node where a user has uploaded FileField content, one or more attached files are deleted. Using Devel prior to import, I can see that the status for all attached files is the same: 1.

It looks like the most recent files are deleted, and only the first migration after attaching files has this effect. For example:

1) Edit, attach FILE_A, then save.
2) Edit, attach FILE_B, then save.
3) Run migrate import: FILE_B is deleted, but not FILE_A.
4) Run migrate import again: no more files are deleted.

I'm using Filefield_paths as well, but 'Retroactive update' and 'Active updating' are not enabled anywhere.

Any input would be very welcome. If there's a migrate hook to skip a row during import, that'd help because I could at least work around this (for me) serious problem. Thanks.

Comments

thekenshow’s picture

I have narrowed my problem down to two Migrate behaviours, both evident in this snippet from node.migrate.inc.

  // Handle an update operation
  if ($row->destid) {
    $node->nid = $row->destid;
    // Need to have the current vid present
    $node->vid = db_result(db_query("SELECT vid FROM {node} WHERE nid=%d", $row->destid));
  }
  // If a nid was provided via mapping, load the existing node
  else if (isset($tblinfo->fields['nid'])) {
    $nidname = $tblinfo->fields['nid']['srcfield'];
    $node = node_load($row->$nidname);
    if (!$node) {
      $node = new stdClass;
      $node->type = $tblinfo->desttype;
    }
  }

1) Migrate doesn't load the existing node for an update operation (it does if the nid is mapped in the content set):
2) Migrate updates the current, existing revision (i.e., does not create a new revision) unless the content set has Create new revision is set to 1.

Because my content type has revisions enabled, during a Migrate node update, the files attached in the current revision are lost when Migrate saves its (incomplete) $node object, because that object was built from scratch and lacks all custom fields that aren't in the content set (as well as those that are in the content set but are unmapped and have no defaults).

If I enable revisions in the content set, it gets worse (all files from all previous revisions are dropped). If I enable filefield support but don't map those fields, the problem stays the same as before.

It looks as though I could use '_migrate_prepare_node' to load the existing node revision and populate the Migrate $node object with the missing pieces from the actual node. Is there an easier solution? Also, I'm curious - why doesn't Migrate doesn't load the existing node for an update?

mikeryan’s picture

Status: Active » Closed (won't fix)

The basic issue is that the primary original motivation for the Migrate module was migrating a site from another system into Drupal. The purpose of updating in that scenario is thus to refresh the Drupal data from the source entirely. In other words, the assumption is that the source data is the system-of-record. To achieve a different update model, you need to implement your own prepare hooks.

In Migrate 2.0 the plan is to support both models natively, and make them explicit - see #753284: Straighten out update scenarios. There is no new development being done on Migrate 1.0, we're focused on 2.0.