mcpField
D
drupal-migration

drupal-migration

github.com/madsnorgaard数据与数据库49133 次安装6 周前更新
代码仓库

关于 drupal-migration

drupal-migration 是面向 Drupal 开发者的 Migrate API 迁移技能,涵盖 Drupal 7 升级、CSV 与 JSON/API 导入、自定义插件,以及通过 Drush 执行和调试迁移。

主要功能

  1. 01Drupal 7 到 10/11 迁移指导
  2. 02CSV 与 JSON/API 数据导入
  3. 03YAML 迁移映射模式
  4. 04自定义源与处理插件
  5. 05使用 Drush 执行和调试

适用场景

  1. 01规划 Drupal 7 网站升级
  2. 02从 CSV 或 API 导入产品或用户数据
  3. 03构建自定义迁移转换

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/madsnorgaard/drupal-agent-resources --skill drupal-migration

安装后在 Claude Code 中输入/drupal-migration确认已加载。

详细介绍

Drupal 迁移专家

你是 Drupal Migrate API 方面的专家,可协助完成从 D7 到 D10/D11 的迁移、CSV 导入和自定义数据迁移。

必备模块

# Core migration modules
drush en migrate migrate_drupal migrate_drupal_ui

# Contrib essentials
composer require drupal/migrate_plus drupal/migrate_tools drupal/migrate_file
drush en migrate_plus migrate_tools migrate_file
模块用途
migrate核心迁移框架
migrate_drupalD6/D7 迁移支持
migrate_drupal_ui基于浏览器的迁移向导
migrate_plus基于配置的迁移、额外的源插件
migrate_tools用于迁移的 Drush 命令
migrate_file文件迁移处理

迁移架构

迁移 YAML 结构
# migrations/migrate_plus.migration.my_migration.yml
id: my_migration
label: 'My Migration'
migration_group: my_group

source:
  plugin: source_plugin_name
  # Source configuration

process:
  # Field mappings
  destination_field: source_field

destination:
  plugin: 'entity:node'
  default_bundle: article

migration_dependencies:
  required:
    - other_migration
关键组件
  1. 源 - 数据的来源(D7 数据库、CSV、JSON API)
  2. 处理 - 在源和目标之间转换数据
  3. 目标 - 数据的去向(节点、用户、分类术语)

D7 到 D10 迁移

设置数据库连接
// settings.php
$databases['migrate']['default'] = [
  'driver' => 'mysql',
  'database' => 'drupal7_db',
  'username' => 'db_user',
  'password' => 'db_pass',
  'host' => 'localhost',
  'prefix' => '',
];
使用 UI
drush en migrate_drupal_ui
# Visit /upgrade to use wizard
使用 Drush(推荐)
# Generate migrations from D7
drush migrate:upgrade --legacy-db-key=migrate --configure-only

# List generated migrations
drush migrate:status

# Run all migrations
drush migrate:import --all

# Run specific migration
drush migrate:import upgrade_d7_node_article

# Rollback
drush migrate:rollback upgrade_d7_node_article
常见的 D7 迁移自定义

使用自定义 YAML 覆盖生成的迁移:

# migrations/migrate_plus.migration.upgrade_d7_node_article.yml
id: upgrade_d7_node_article
label: 'Article nodes from D7'
migration_group: migrate_drupal_7

source:
  plugin: d7_node
  node_type: article

process:
  type:
    plugin: default_value
    default_value: article
  title: title
  uid:
    plugin: migration_lookup
    migration: upgrade_d7_user
    source: uid
  body:
    plugin: sub_process
    source: body
    process:
      value: value
      format:
        plugin: static_map
        source: format
        map:
          full_html: full_html
          filtered_html: basic_html
        default_value: basic_html
  field_image:
    plugin: migration_lookup
    migration: upgrade_d7_file
    source: field_image/0/fid

destination:
  plugin: 'entity:node'
  default_bundle: article

migration_dependencies:
  required:
    - upgrade_d7_user
    - upgrade_d7_file

CSV 迁移

源插件配置
# migrations/migrate_plus.migration.import_products.yml
id: import_products
label: 'Import products from CSV'
migration_group: imports

source:
  plugin: csv
  path: 'modules/custom/my_module/data/products.csv'
  ids:
    - sku
  header_row_count: 1
  # Optionally define columns explicitly
  column_names:
    0:
      sku: 'Product SKU'
    1:
      name: 'Product Name'
    2:
      price: 'Price'
    3:
      category: 'Category'

process:
  type:
    plugin: default_value
    default_value: product
  title: name
  field_sku: sku
  field_price: price
  field_category:
    plugin: entity_lookup
    source: category
    entity_type: taxonomy_term
    bundle: product_categories
    bundle_key: vid
    value_key: name

destination:
  plugin: 'entity:node'
  default_bundle: product
运行 CSV 迁移
# Import
drush migrate:import import_products

# Update existing records
drush migrate:import import_products --update

# Reset status if stuck
drush migrate:reset-status import_products

JSON/API 迁移

HTTP JSON 源
id: import_api_users
label: 'Import users from API'

source:
  plugin: url
  data_fetcher_plugin: http
  data_parser_plugin: json
  urls:
    - 'https://api.example.com/users'
  item_selector: data
  ids:
    id:
      type: integer
  fields:
    - name: id
      selector: id
    - name: email
      selector: email
    - name: full_name
      selector: attributes/name

process:
  name: full_name
  mail: email
  init: email
  status:
    plugin: default_value
    default_value: 1

destination:
  plugin: 'entity:user'

常见处理插件

基本转换
process:
  # Direct mapping
  title: source_title

  # Default value
  status:
    plugin: default_value
    default_value: 1

  # Static mapping
  field_type:
    plugin: static_map
    source: type
    map:
      old_type_1: new_type_1
      old_type_2: new_type_2
    default_value: default_type

  # Concatenate
  title:
    plugin: concat
    source:
      - first_name
      - last_name
    delimiter: ' '

  # Substring
  field_summary:
    plugin: substr
    source: body
    start: 0
    length: 200
实体引用
process:
  # Migration lookup (referenced entity was migrated)
  uid:
    plugin: migration_lookup
    migration: users
    source: author_id

  # Entity lookup (entity already exists)
  field_category:
    plugin: entity_lookup
    source: category_name
    entity_type: taxonomy_term
    bundle: categories
    bundle_key: vid
    value_key: name

  # Entity generate (create if not exists)
  field_tags:
    plugin: entity_generate
    source: tags
    entity_type: taxonomy_term
    bundle: tags
    bundle_key: vid
    value_key: name
多个值
process:
  # Handle multiple values
  field_tags:
    plugin: sub_process
    source: tags
    process:
      target_id:
        plugin: entity_generate
        source: name
        entity_type: taxonomy_term
        bundle: tags
        value_key: name

  # Explode string to array
  field_keywords:
    - plugin: explode
      source: keywords
      delimiter: ','
    - plugin: entity_generate
      entity_type: taxonomy_term
      bundle: keywords
      value_key: name
条件处理
process:
  # Skip if empty
  field_image:
    plugin: skip_on_empty
    method: process
    source: image_url

  # Skip row if condition
  pseudo_skip:
    plugin: skip_on_value
    source: status
    method: row
    value: 'draft'

自定义源插件

<?php

declare(strict_types=1);

namespace Drupal\my_module\Plugin\migrate\source;

use Drupal\migrate\Attribute\MigrateSource;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Row;

/**
 * Custom source for legacy products.
 */
#[MigrateSource(
  id: 'legacy_products',
  source_module: 'my_module',
)]
class LegacyProducts extends SqlBase {

  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = $this->select('legacy_products', 'p');
    $query->fields('p', ['id', 'name', 'price', 'description']);
    $query->condition('p.status', 'active');
    $query->orderBy('p.id');
    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function fields() {
    return [
      'id' => $this->t('Product ID'),
      'name' => $this->t('Product name'),
      'price' => $this->t('Price'),
      'description' => $this->t('Description'),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    return [
      'id' => [
        'type' => 'integer',
        'alias' => 'p',
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    // Add computed fields or modify data
    $price = $row->getSourceProperty('price');
    $row->setSourceProperty('price_with_tax', $price * 1.21);

    return parent::prepareRow($row);
  }

}

自定义处理插件

<?php

declare(strict_types=1);

namespace Drupal\my_module\Plugin\migrate\process;

use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;

/**
 * Converts price from cents to decimal.
 *
 * Example usage:
 * @code
 * process:
 *   field_price:
 *     plugin: cents_to_decimal
 *     source: price_cents
 * @endcode
 */
#[MigrateProcess(id: 'cents_to_decimal')]
class CentsToDecimal extends ProcessPluginBase {

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    if (empty($value) || !is_numeric($value)) {
      return NULL;
    }

    return number_format((float) $value / 100, 2, '.', '');
  }

}

Drush 命令参考

# List all migrations
drush migrate:status

# Run migration
drush migrate:import migration_id

# Run with options
drush migrate:import migration_id --limit=100
drush migrate:import migration_id --update
drush migrate:import migration_id --sync

# Rollback
drush migrate:rollback migration_id

# Reset stuck migration
drush migrate:reset-status migration_id

# Stop running migration
drush migrate:stop migration_id

# Show messages/errors
drush migrate:messages migration_id

调试迁移

启用详细输出
drush migrate:import migration_id -vvv
检查迁移状态
# Add to migration YAML
migration_tags:
  - debug
记录处理结果
// In custom process plugin
\Drupal::logger('my_migration')->notice('Processing: @value', ['@value' => $value]);
常见问题

“迁移正在运行”:

drush migrate:reset-status migration_id

内存错误:

drush migrate:import migration_id --limit=500
# Process in batches

缺少依赖项: 检查 YAML 中的 migration_dependencies 是否与实际迁移 ID 相符。

最佳实践

  1. 始终使用迁移组来组织相关迁移
  2. 设置 migration_dependencies以确保顺序正确
  3. **在完整导入前使用 --limit=10**进行测试
  4. **使用 --update**重新运行已更新的迁移
  5. 保留源数据,直到确认迁移无误
  6. 在迁移 YAML 注释中记录字段映射
  7. 在生产环境迁移前制定回滚计划
  8. 监控大型迁移的内存使用情况

迁移模块结构

my_migration/
├── my_migration.info.yml
├── my_migration.module
├── config/
│   └── install/
│       ├── migrate_plus.migration_group.my_group.yml
│       ├── migrate_plus.migration.users.yml
│       └── migrate_plus.migration.content.yml
├── src/
│   └── Plugin/
│       └── migrate/
│           ├── source/
│           │   └── LegacyProducts.php
│           └── process/
│               └── CentsToDecimal.php
└── data/
    └── import.csv

来源

评论

支持 Markdown