Disabling functionality temporarily during migration

Continuing with techniques from the “Acme” project, the location content type had an address field and a geofield, with field_geofield configured to automatically determine latitude and longitude from the associated field_address - a fact I was initially unaware of. Our source data contained latitude and longitude already, which I mapped directly in the migration:

 field_geofield:
   plugin: geofield_latlon
   source:
     - latitude
     - longitude

However, testing location migrations by repeatedly running the import, I soon started getting messages from Google Maps API that my daily quota had been exceeded, and quickly tracked down the integration with field_address. Clearly, the calls out to Google Maps were both unnecessary and hazardous - how to prevent them? Fortunately, the migration system provides events which fire before and after each migration is executed. So, we subscribe to MigrateEvents::PRE_IMPORT to save the current settings and disable the external call:

public function onMigrationPreImport(MigrateImportEvent $event) {
   if ($event->getMigration()->id() == 'location') {
     $fields = \Drupal::entityTypeManager()->getStorage('field_config')->loadByProperties(['field_name' => 'field_geofield']);
     if ($fields) {
        /** @var \Drupal\field\Entity\FieldConfig $field */
        if ($field = $fields['node.location.field_geofield']) {
         $this->originalSettings = $field->getThirdPartySettings('geocoder_field');
         $field->setThirdPartySetting('geocoder_field', 'method', 'none');
         $field->save();
        }
     }
   }
 }

And we subscribe to MigrateEvents::POST_IMPORT to restore the original settings:

 public function onMigrationPostImport(MigrateImportEvent $event) {
   if ($event->getMigration()->id() == 'location') {
     $fields = \Drupal::entityTypeManager()->getStorage('field_config')->loadByProperties(['field_name' => 'field_geofield']);
     if ($fields) {
       /** @var \Drupal\field\Entity\FieldConfig $field */
        if ($field = $fields['node.location.field_geofield']) {
         foreach ($this->originalSettings as $key => $value) {
           $field->setThirdPartySetting('geocoder_field', $key, $value);
         }
         $field->save();
        }
     }
   }
 }

The thoughtful reader may note a risk here - what if someone were adding or editing a location node while this were running? The geofield would not be populated from the address field. In this case, this is not a problem - this is a one-time bulk migration (and no one should be making changes on a production website at such a time). In cases involving an ongoing feed where the feed data is used as-is on the Drupal site, it would also not be a problem, although if there were a practice of manually editing imported content there would be some risk.

Use the Twitter thread below to comment on this post: