Avoid sending emails while doing a migration on Drupal 8

Submitted by on

During a migration, Drupal reads the data from an external source and creates content in our new Drupal Site. While doing that, Drupal executes all hooks and events related to creating the new content. So any implementations of hook_entity_insert() are triggered for every new entity saved on our new site.

This can be a problem if we have some features in our new site which have an effect beyond the site and are executed when any new content is created, such as sending a tweet or sending an email. When we run the migration we will have a ton of emails or tweets from the old content. Usually, that is not the expected nor desired behavior.

Fortunately, in Drupal 8 the migrations are Events and we can create an EventSubscriber (more about EventSubscribers here) which will allow us to create a flag before the migration runs so we can determine in our code if the entity has been created during a migration or not.

The main idea was taken from this Moshe Weitzman gist. (Thanks!) I will add just the missing parts.

First, we generate all the event subscriber related files using this Drupal Console command:

 drupal generate:event:subscriber

The console will ask some questions (in which module do we want to generate the EventSubscriber and the name of the service):

 Enter the module name [config_log]:
 > your_module

 Enter the service name [simple_faq.default]:
 > migration_events.subscriber

 Class name [DefaultSubscriber]:
 > MigrationEvents

 Enter event name [ ]:
 >

 Do you want to load services from the container (yes/no) [no]:
 > no

 Do you confirm generation? (yes/no) [yes]:
 >yes

This will generate two files:

modules/custom/your_module/your_module.services.yml

Which basically lets Drupal know that we have a Subscriber there which needs to be executed and:

modules/custom/your_module/src/EventSubscriber/MigrationEvents.php

With this content:

namespace Drupal\simple_faq\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\Event;

/**
 * Class MigrationEvents.
 *
 * @package Drupal\simple_faq
 */
class MigrationEvents implements EventSubscriberInterface {

  /**
   * Constructs a new MigrationEvents object.
   */
  public function __construct() {

  }

  /**
   * [email protected]}
   */
  static function getSubscribedEvents() {

    return $events;
  }

}

We need to add our flag in this file which will indicate to Drupal that we are running the migration. First, we need to import the Migrate events, at the top of our MigrationEvents.php file:

use Drupal\migrate\Event\MigrateImportEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\migrate\Event\MigrateEvents;

And then after add our methods, within the MigrationEvents class:

   protected $staticCache;

  public function __construct() {
    $this->staticCache = &drupal_static("your_migration");
  }

  /**
   * [email protected]}
   */
  public static function getSubscribedEvents() {
    return [
      MigrateEvents::PRE_IMPORT => 'onMigratePreImport',
      MigrateEvents::POST_IMPORT => 'onMigratePostImport',
    ];
  }

  /**
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   Import Event.
   */
  public function onMigratePostImport(MigrateImportEvent $event) {
    if ($event->getMigration()->getBaseId() == "your_migration") {
      $this->staticCache = FALSE;
    }
  }

  /**
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   Import Event.
   */
  public function onMigratePreImport(MigrateImportEvent $event) {
    if ($event->getMigration()->getBaseId() == "your_migration") {
      $this->staticCache = TRUE;
    }
  }

And that's it, now we have a flag which we can use to determine if we are running the migration or not, the complete class look like this:

namespace Drupal\your_module\EventSubscriber;

use Drupal\migrate\Event\MigrateImportEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\migrate\Event\MigrateEvents;

/**
 * Event subscriber to avoid sending emails/tweets/facebook posts on migrations.
 */
class MigrationEvents implements EventSubscriberInterface {

  /**
   * The drupal_static cache.
   *
   * @var array
   */
  protected $staticCache;

  /**
   * CommentEventSubscriber constructor.
   */
  public function __construct() {
    $this->staticCache = &drupal_static("your_migration");
  }

  /**
   * [email protected]}
   */
  public static function getSubscribedEvents() {
    return [
      MigrateEvents::PRE_IMPORT => 'onMigratePreImport',
      MigrateEvents::POST_IMPORT => 'onMigratePostImport',
    ];
  }

   /**
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   Import Event.
   */
  public function onMigratePostImport(MigrateImportEvent $event) {
    if ($event->getMigration()->getBaseId() == "your_migration") {
      $this->staticCache = FALSE;
    }
  }

  /**
   * @param \Drupal\migrate\Event\MigrateImportEvent $event
   *   Import Event.
   */
  public function onMigratePreImport(MigrateImportEvent $event) {
    if ($event->getMigration()->getBaseId() == "your_migration") {
      $this->staticCache = TRUE;
    }
  }
}

And finally, we now can use this variable to determine if we should send that email when creating a new entity, for instance:

/**
 * Implements hook_node_insert().
 */
function yourmodule_node_insert($entity) {
  // If the migration is running, just return without doing anything.
  if (drupal_static('your_migration', FALSE)) {
    return;
  }
  // All your code for sending emails/tweets is here.
  // . . .
}

And that's it.

Here we used drupal_static to preserve the value through the execution of the migration. If you want to read more about it, check here

Comments

Submitted by benjy on Thu, 05/11/2017 - 07:20

Or, just swap out the mail-system before you run the migrations, I patched migrate_drush_run with


function drush_migrate_drush_run($migrations) {
+ \Drupal::service('config.factory')
+ ->getEditable('mailsystem.settings')
+ ->set('defaults', [
+ 'sender' => 'test_mail_collector',
+ 'formatter' => 'test_mail_collector',
+ ])->save();

Submitted by on Sat, 07/01/2017 - 01:41

I didn't even know about the "Migrate drush" module.

Thanks for shared this.

David.

Add new comment