关于 drupal-migration
drupal-migration 是面向 Drupal 开发者的 Migrate API 迁移技能,涵盖 Drupal 7 升级、CSV 与 JSON/API 导入、自定义插件,以及通过 Drush 执行和调试迁移。
主要功能
- 01Drupal 7 到 10/11 迁移指导
- 02CSV 与 JSON/API 数据导入
- 03YAML 迁移映射模式
- 04自定义源与处理插件
- 05使用 Drush 执行和调试
适用场景
- 01规划 Drupal 7 网站升级
- 02从 CSV 或 API 导入产品或用户数据
- 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_drupal | D6/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
关键组件
- 源 - 数据的来源(D7 数据库、CSV、JSON API)
- 处理 - 在源和目标之间转换数据
- 目标 - 数据的去向(节点、用户、分类术语)
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 相符。
最佳实践
- 始终使用迁移组来组织相关迁移
- 设置 migration_dependencies以确保顺序正确
- **在完整导入前使用
--limit=10**进行测试 - **使用
--update**重新运行已更新的迁移 - 保留源数据,直到确认迁移无误
- 在迁移 YAML 注释中记录字段映射
- 在生产环境迁移前制定回滚计划
- 监控大型迁移的内存使用情况
迁移模块结构
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