Migration

switch_roles.install
<?php

use Drupal\user\RoleInterface;

/**
 * Remove the old roles and replace them with the new ones.
 */
function MY_MODULE_update_9041(): void {
  $em = \Drupal::entityTypeManager();
  $user_storage = $em->getStorage('user');

  // Ensure the new role exists. If not, create it first.
  $role_storage = $em->getStorage('user_role');
  if ($role_storage->load('new_role') === NULL) {
    /** @var \Drupal\user\RoleInterface $role */
    $role = $role_storage->create([
      'id' => 'new_role',
      'label' => 'New role',
    ]);
    $role->save();
  }

  $uids = \Drupal::entityQuery('user')
    ->accessCheck(FALSE)
    ->execute();

  if (empty($uids)) {
    return;
  }

  /** @var \Drupal\user\UserInterface[] $users */
  $users = $user_storage->loadMultiple($uids);

  foreach ($users as $user) {
    if ($user->hasRole('old_role')) {
      $user->addRole('new_role');
      $user->removeRole('old_role');
    }

    $user->save();
  }
}
02.04.2026 | Lothar Ferreira Neumann

Updating user roles using a module update hook

query_manipulate.php
<?php

namespace Drupal\my_module_migrate\Plugin\migrate\source\d8;

use Drupal\migrate\Row;

/**
 * Base class for D8 source plugins to collect field values from Field API.
 *
 *  Available configuration keys:
 *   - id: (optional) The id of the content which should get migrated. This can
 *     be useful to only migrate a selected set of nodes. Excepts multiple ids.
 *
 * @MigrateSource(
 *   id = "my_module_d8_gallery",
 *   source_provider = "my_module_migrate"
 * )
 */
class MyModuleGallery extends ContentEntity {

  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = parent::query();

    if (isset($this->configuration['id'])) {
      $entityDefinition = $this->entityTypeManager->getDefinition($this->configuration['entity_type']);
      $idKey = $entityDefinition->getKey('id');
      $query->condition("d.{$idKey}", $this->configuration['id'], 'IN');
    }

    // Left join to get the nid of the old image node.
    $query->leftJoin('paragraph__field_referenzfeld_galerie', 'pfrg', 'pfrg.entity_id = b.id AND pfrg.revision_id = b.revision_id');
    $query->leftJoin('node__field_gallery_bild', 'nfgb', 'nfgb.entity_id = pfrg.field_referenzfeld_galerie_target_id');

    $query->leftJoin('node__field_base_public_title', 'nfbpt', 'nfbpt.entity_id = pfrg.field_referenzfeld_galerie_target_id');

    $query->addExpression('GROUP_CONCAT(nfgb.field_gallery_bild_target_id)', 'gallery_image_ids');
    // Add public title field.
    $query->addField('nfbpt', 'field_base_public_title_value', 'field_base_public_title_value');

    $query->groupBy('b.id');

    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    $return = parent::prepareRow($row);

    $nids = [];
    $ids_string = $row->getSourceProperty('gallery_image_ids');
    if (!empty($ids_string)) {
      $ids = explode(',', $ids_string);

      foreach ($ids as $id) {
        $nids[] = ['nid' => (int) $id];
      }
      // Add new source property to skip old gallery node within migration.
      $row->setSourceProperty('field_referenzfeld_galerie', $nids);
    }
    $row->setSourceProperty('field_base_public_title', $row->getSourceProperty('field_base_public_title_value'));

    return $return;
  }

}
query.sql
SELECT 
  GROUP_CONCAT(nfgb.field_gallery_bild_target_id), 
  nfbpt.field_base_public_title_value
FROM paragraph__field_referenzfeld_galerie AS pfrg
LEFT JOIN node__field_gallery_bild AS nfgb
  ON nfgb.entity_id = pfrg.field_referenzfeld_galerie_target_id
LEFT JOIN node__field_base_public_title AS nfbpt
  ON nfbpt.entity_id = pfrg.field_referenzfeld_galerie_target_id
WHERE pfrg.entity_id = 100810 AND pfrg.revision_id = 1919384

 

cleanup_aliases.php
<?php

/** @var \Drupal\path_alias\PathAliasStorage */
$alias_storage = \Drupal::entityTypeManager()->getStorage('path_alias');
$db = \Drupal::database();

$langcodes = array_keys(\Drupal::languageManager()->getLanguages());

$total = 0;
$duplicates = "";

// Get a list of all distinct aliases.
$query = $db->select('path_alias', 'pa')
  ->fields('pa', ['alias'])
  ->orderBy('alias')
  ->distinct();
$all_aliases = $query->execute()->fetchAll(\Pdo::FETCH_COLUMN);

foreach ($all_aliases as $alias) {
  // Some aliases are 'NULL'.
  if (!$alias) {
    continue;
  }

  // We only look for duplicates within the langcode.
  foreach ($langcodes as $langcode) {
    // (1) Get the newest ID for that alias and langcode.
    $query = $db->select('path_alias', 'pa')
      ->fields('pa', ['id'])
      ->condition('alias', $alias)
      ->condition('langcode', $langcode)
      ->orderBy('id', 'DESC')
      ->range(0, 1);
    $newest_id = $query->execute()->fetchField(0);
    if (!$newest_id) {
      // There is no alias for that langcode.
      // So there are also no duplicates.
      continue;
    }

    // (2) Select all ids lower than it with the same alias and langcode.
    $query = $db->select('path_alias', 'pa')
      ->fields('pa', ['id'])
      ->condition('alias', $alias)
      ->condition('langcode', $langcode)
      ->condition('id', $newest_id, '<');
    $duplicate_ids = $query->execute()->fetchAll(\PDO::FETCH_COLUMN);

    if (!str_starts_with($alias, "/")) {
        $query = $db->select('path_alias', 'pa')
        ->fields('pa', ['id'])
        ->condition('alias', "/" . $alias)
        ->condition('langcode', $langcode);
        $ids_with_slash = $query->execute()->fetchAll(\PDO::FETCH_COLUMN);
        if (count($ids_with_slash) > 0) {
            // We can safely delete the one without.
            $to_delete = $alias_storage->loadByProperties([
                'alias' => $alias,
                'langcode' => $langcode,
            ]);
            $alias_storage->delete($to_delete);
        } else {
            // It's the only one? Update with slash.
            $alias_entitys = $alias_storage->loadByProperties([
                'alias' => $alias,
                'langcode' => $langcode,
            ]);
            if (!empty($alias_entitys)) {
                $alias_entity = reset($alias_entitys);
                $alias_entity->set('alias', '/' . $alias);
                $alias_entity->save();
            }
        }
    }

    // We delete those with the alias storage since we want Drupal to handle it
    // and it will delete revisions as well.
    $duplicate_aliases = $alias_storage->loadMultiple($duplicate_ids);
    $total += count($duplicate_aliases);
    if (count($duplicate_aliases) > 0) {
        $duplicates = $duplicates . $alias . PHP_EOL;
    }
    $alias_storage->delete($duplicate_aliases);
  }
}

echo(sprintf("Deleting %d duplicate aliases..." . PHP_EOL, $total));
echo($duplicates);
echo("DONE" . PHP_EOL);
21.02.2025 | Nikolas Kopp

Clean up migrated path aliases

drush_migrate_status.sh
drush migrate:status

Display a summary of the status of your migrations.

drush_migrate_import.sh
drush migrate:import

Trigger the import process for migrations.

drush_migrate_reset_status.sh
drush migrate:reset-status

Reset the migration statuses if your migration get stuck.

drush_migrate_rollback.sh
drush migrate:rollback

Rollback your migrations by undoing changes made.

drush_migrate_stop.sh
drush migrate:stop

 Stop a running migration gracefully.

drush_migrate_field_source.sh
drush migrate:fields-source

List field sources of your sources plugin.

drush_migrate_message.sh
drush migrate:messages

Show migration messages.

17.05.2024 | Michael Ebert

Drush Migrate Commands