2

I have a migration that pulls in a PDF with it and populates a content type. When I rollback the migration, it does not delete the PDFs with it.

How can I tell a migration on rollback to clean up after itself? Is there something I can put in the YAML? Is there an event I can hook into?

2
  • Files aren't typically deleted immediately, they're marked as temporary and cleared out in a cron run. Check the file_managed table to see if the rollback marks the file(s) as temporary; if it does, you can either wait as normal for cron to kick in, or decide to hook into the end of the migration process through code and force the cron methods through manually
    – Clive
    Mar 5, 2019 at 16:54
  • I want them purged ASAP, dev gets slowed down otherwise. I wound up implementing a custom destination plugin that extends EntityContentBase and implemented a rollback method to deal with it. I wish there was a simple flag for this in the migration YAML.
    – Kevin
    Mar 5, 2019 at 18:00

2 Answers 2

1

I wound up doing this to solve this case:

<?php

namespace Drupal\mymodule\Plugin\migrate\destination;

use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
use Drupal\migrate\Plugin\MigrationInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\node\NodeInterface;

/**
 * We need rollback support for deleting files.
 *
 * @MigrateDestination(
 *   id = "myplugin"
 * )
 */
class MyPlugin extends EntityContentBase {

  /** @var string $entityType */
  public static $entityType = 'node';

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
    return parent::create($container, $configuration, 'entity:' . static::$entityType, $plugin_definition, $migration);
  }

  /**
   * {@inheritdoc}
   */
  public function rollback(array $destination_identifier) {
    $entity = $this->storage->load(reset($destination_identifier));

    // Delete attached files on Working Papers.
    if ($entity && $entity instanceof NodeInterface) {
      if ($entity->bundle() === 'working_paper') {
        $fid = $entity->get('field_paper_working_paper')->target_id;

        if ($fid) {
          $storage_handler = \Drupal::entityTypeManager()->getStorage('file');
          $entities = $storage_handler->load($fid);
          $storage_handler->delete([$entities]);
        }
      }
    }

    // Execute the normal rollback from here.
    parent::rollback($destination_identifier);
  }

}

In the migration yaml definition, point destination at this instead of entity:node:

destination:
  plugin: myplugin
  bundle: working_paper

The $entityType member and create method seemed to be required as well, otherwise Migrate did not seem to know how to parse this into a node of a particular type, despite extending from EntityContentBase.

The reason for wanting to do this is that its cumbersome especially while developing that files are not removed along with their entity on rollback. In my case, I have strictest confidence in that the rollback of this entity does not affect anything else because this is the only place this file will ever appear.

Is this the best way to add this type of behavior?

0

In my configuration migration files I have a bunch of files generated and two of them are my_migration_file_private and my_migration_file

When I drush mr I add this migrations explicitly to rollback and the magic is done in db and files folders

Hope it helps, it works for me

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.