Описание
Модуль Migrate это фреймворк для миграции (импорта) данных в Drupal из любых источников. Например с помощью этого модуля можно перенести контент из сторонней CMS, или просто сделать миграцию с одной ветки друпала на другую (например 5 → 7).
Из коробки модуль умеет импортировать данные в:
- ноды
- пользователей
- комментарии
- термины таксономии
- блоки
- любые сущности
- файлы
- меню и пункты меню
- переменные
- произвольные таблицы бд
При необходимости можно написать свой destination плагин.
Основные отличия от других способов миграции (Feeds, Node Export/Node Import и т.д.):
- Полный контроль над процессом миграции и над данными.
- Любой источник данных (теоретически). Из коробки это XML, CSV, XLS, JSON, IBM DB2, MongoDB, MSSQL, Oracle, файлы.
- Поддержка всех Drupal 7 сущностей и полей.
- Возможность сделать rollback после импорта, т.е. отменить все изменения.
- Статистика по каждой миграции.
- Зависимые миграции.
- Интеграция с Drush.
Использование
Для начала переноса контента нужно создать модуль, реализовать в нём хук hook_migrate_api()
и написать классы миграции, расширяющие Migration
.
Одна миграция может импортировать только один тип данных (один bundle в терминологии Drupal 7), например ноды определённого типа или термины таксономии определённого словаря.
Для примера создадим модуль example_migration
, который будет заниматься миграцией данных из mysql таблицы pages
в ноды типа page
.
1. Реализация hook_migrate_api()
Добавляем в файл example_migration.migrate.inc
:
/**
* Implement hook_migrate_api()
*/
function example_migration_migrate_api() {
return array(
'api' => 2,
'groups' => array(
'example' => array(
'title' => 'Example',
),
),
'migrations' => array(
'Pages' => array(
'class_name' => 'PagesMigration',
'group_name' => 'example',
),
),
);
}
В хуке указывается версия api, название группы и список ваших миграций. Подробнее.
2. Реализация класса миграции
Создаём файл PagesMigration.inc
и добавляем:
class PagesMigration extends Migration {
public function __construct($arguments) {
parent::__construct($arguments);
}
}
Добавляем в example_migration.info
информацию о файле, в котором реализован класс:
files[] = PagesMigration.inc
Сбрасываем кэш.
3. Описание источника данных
В методе __construct
, с помощью Database API, делаем выборку из источника и заполняем переменную $this->source
:
$query = db_select('pages', 'p')->fields('p', array('pgid', 'page_title', 'page_body'));
$this->source = new MigrateSourceSQL($query);
В примере подразумевается что таблица pages
находится в одной бд с друпалом. Если это не так, то код немного меняется:
$query = Database::getConnection('default', 'otherdb')->select('pages', 'p')->fields('p', array('pgid', 'page_title', 'page_body'));
$this->source = new MigrateSourceSQL($query, array(), NULL, array('map_joinable' => FALSE));
4. Описание цели миграции
В методе __construct
заполняем переменную $this->destination
:
$this->destination = new MigrateDestinationNode('page');
В качестве параметра MigrateDestinationNode()
указывается машинное имя материала.
5. Описание ключевых полей источника и цели
Модуль Migrate поддерживает откат изменений и обновление уже импортированных данных. Для правильной работы этих функций нужно в методе __construct
заполнить переменную $this->map
информацией о первичных ключах источника и цели:
$source_key_schema = array(
'pgid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
)
);
$this->map = new MigrateSQLMap($this->machineName, $source_key_schema, MigrateDestinationNode::getKeySchema());
Вызов метода MigrateDestinationNode::getKeySchema()
равносилен коду:
array(
'nid' => array(
'type' => 'int',
'unsigned' => TRUE,
'description' => 'ID of destination node',
),
)
6. Маппинг полей
В методе __construct
, с помощью Migrate::addFieldMapping()
, делаем маппинг полей:
$this->addFieldMapping('title', 'page_title');
$this->addFieldMapping('body', 'page_body');
Первый параметр — это поле цели, второй — поле источника.
Если включить модуль Migrate UI и на странице admin/content/migrate
кликнуть по имени миграции, то можно будет посмотреть советы по маппингу:
Итого
Полный листинг класса миграции:
class PagesMigration extends Migration {
public function __construct($arguments) {
parent::__construct($arguments);
// Source
$query = db_select('pages', 'p')->fields('p', array('pgid', 'page_title', 'page_body'));
$this->source = new MigrateSourceSQL($query);
// Destination
$this->destination = new MigrateDestinationNode('page');
// Key schema
$source_key_schema = array(
'pgid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
)
);
$this->map = new MigrateSQLMap($this->machineName, $source_key_schema, MigrateDestinationNode::getKeySchema());
// Mapping
$this->addFieldMapping('title', 'page_title');
$this->addFieldMapping('body', 'page_body');
}
}
После написания миграции идём на страницу admin/content/migrate
, переходим в группу Example, отмечаем нужную миграцию, выбираем операцию Import и жмём Execute:
Полезные ссылки
— Пример миграции данных из Drupal 6 в Drupal 7
— Пример миграции данных из Drupal 5 в Drupal 7
— Пример миграции данных из PHPBB3 в Drupal 7
— Официальная документация
— Content migration using the Migrate module (видео)
— Импорт данных с фреймворком Migrate (доклад Владислава Богатырева)
— Импорт данных в Drupal - легко и просто (доклад Дмитро Данилевский)
— Мои посты про Migrate
Комментарии
Как всегда радуете толковой информацией, спасибо. Не добрался ещё до этого модуля, но со временем буду в нем разбираться. Есть ещё такая возможность применения http://www.lullabot.com/articles/drupal-data-imports-migrate-and-table-… с использованием модуля table wizard
table wizard для шестёрки
в Вашем блоге всегда можно найти что-то интересное и новое для себя, спасибо)
не подскажете как проще доработать рабочий сайт, не переводя его в режим обслуживания на период обновления/доработки?
полагаю данный модуль может помочь в данном вопросе, провести все необходимые работы над сайтом а затем с "живого" сайта перекинуть все материалы на новую версию...
Вы не сталкивались с этим, возможно подскажете, как лучше провести обновления?
именно так. сам процесс миграции занимает считанные минуты
Не совсем уверен на счёт статистики по каждой миграции и зависимых миграций. Но всё остальное в Feeds есть, за исключением интеграции с Drush, которая уже на подходе.
как в feeds скопировать файлы из одного места в другое?
как быть если нет возможности сохранить primary key? т.е импортировать юзеров без сохранения pk, а потом ноды?
как откатывать импорты?
как импортировать сложные поля вроде address, date или кастомного составного поля?
как внедрить свои настройки в импорт?
как в одни клик сделать миграцию всех данных (юзеры, ноды, термины)?
и главный вопрос как это всё отлаживать?
feeds умеет закачивать файлы, т.е. к примеру отправить картинку в field_image можно без проблем. Если что то не стандартное, то через собственный плагин.
не знаю что имеется в виду, НИДы для ноды тоже можно задавать при импорте
Есть такая возможность. Хотя, точно не помню, потому что ни разу не пользовался. Обычно полагаюсь на стандартный бекап сайта.
date и addressfield имеют интеграцию с Feeds поэтому можно с ними работать так же как и с остальными полями. Для собственных составных полей можно сделать плагин-маппер.
Есть UI с кучей настроек, можно расширить его через API
Как обычно.
если импортировать юзеров без сохранения pk, то не понятно как потом импортировать ноды, где uid уже будет не актуальным. в Migrate для этого есть зависимости миграций.
т.е. никак :)
Врать не буду, последний раз Фидс запускал почти год назад. Насколько помню он при импорте сохраняет PK каждой исходной записи в своей собственной таблице, с тем чтобы можно было их связывать при следующем импорте или просто чтобы откатится при необходимости.
А что в Майгрэйте какая то особенная отладка есть?
ну если учесть что миграция это класс, в котором можно наставить брикпоинтов на любую стадию импорта, то по сравнению с feeds, да, особенная :)
для меня feeds это чёрный ящик в который приходят данные, он что-то там крутит и выдаёт ноду. в migrate же всё прозрачно.
А можно пример как отправить картинку в field_image ?
модуль состоит из 2х файлов?
example_migration.info
example_migration.module
в example_migration.module вставляется хук и класс?
на странице admin/content/migrate после включения модуля ничего не появляется
кстати тут http://drupal.org/node/1006982 как я понял, теперь надо в inc файле объявлять класс в версии Migrate 2.5 и выше. может в этом проблема?
Тут сообщают про новую модную штучку для обновления в Migrate:
track_changes
Начиная с версии 2.6 Migrate умеет сам определять, изменился ли контент в сорсе с момента последнего запуска импорта.
Вопрос - почему своя миграция не появляется в списке /admin/content/migration?
Друпал 7, модуль свой написал, хуки есть, цель импорт из CSV в свою таблицу MySQL.
может что-то не так пишу?
Спасибо.
класс нужно зарегистрировать в .info файле
так есть это
name = CSV to DB Table
description = Allows to import CSV-files to custom MySQL table.
version = "7.x-1.0"
core = "7.x"
package = "CustomAddedModules"
dependencies[] = migrate
files[] = csvtotable.module
почитайте маны, там что-то менялось в новых версиях
описал класс в файле csvtotable.migrate.inc, прицепил его, в .module остался только хук. теперь импортер появляется в списке migrate, но при импорте валится с ошибками.
Undefined property: stdClass::$id File
Undefined property: stdClass::$TableNumber
Undefined property: stdClass::$TableString
Column not found: 1054 Unknown column 'map.sourceid2' in 'where clause'
Не подскажете, чем может быть вызвано, что-то не так описал в коде?
TableString TableNumber id - это поля в таблице.
Разобрался и все настроил. Выкладываю ниже код класса, который надо прописать в файле имя_модуля.migrate.inc (.inc не забываем прописать в .info, в .module оставляем только хук) для импорта данных из CSV в таблицу БД MySQL. Думаю, втор блога не будет против)))
Здравствуйте. У меня есть задача сделать обновление нод на сайте. То есть есть поле "код", надо по этому полю обновлять поле "Цена". пишу миграцию по Вашему примеру, не могли Вы проверить где у меня ошибка? Вот код
Спасибо.
с виду правильно
А с чем может быть связана вот эта ошибка? Файл на сервере есть, по ссылке открывает.
Сейчас еще вылезла вот такая ошибка
может это из-за нее моя миграция не работает?
решил свою задачу выше с помощью модулей feeds и data - удобнее, в части интерфейса для пользователя, именно импорт из CSV в таблицы MySQL.
в конструкторе MigrateSourceCSV нужно указывать полный путь к файлу в файловой системе. не думаю, что у вас он лежит в /sites/default/files/feeds/update.csv
Все я разобрался с этим. Теперь осталось написать правильный обработчик ключевого поля в файле. Не подскажете? А то я все смотрел с d.org, а там про ключи найти не могу. Все дело в том что я хочу обновлять значение поля "цена", по значению поля "код товара". Пока что код для ключевого поля вот такой
Я подправил все предыдущие ошибки и теперь после импорта просто создает новые ноды, а не обновляет уже существующие.
Еще вот такой вопрос http://clip2net.com/s/5mkCU0 . Можете объяснить?
я feeds использую просто для импорта нод. но у меня условие от зака обновлять по коду, так как в 1С не все названия совпадают с заголовками на сайте. На сайте около 15к нод, около 6к не совпадают в заголовке.
В feeds нет возможности установить любое ключевым - только url, guid, title. Пробовал ставить модуль Unique Field - не помогло.
Дмитрий, я сделал так - тыц, дальше не копал.
Пасиб, попробую вашим способом
$pathSourceFile = file_default_scheme() . '://feeds/blog.csv';
Уже долгое время бьюсь с этим модулем, делал все как в статье... не получается... может есть какой-то полный пример решения задачи?!
https://www.drupal.org/node/415260
Да, там был... пытался разобраться, но видимо моих знаний недостаточно дабы постичь в одиночку ;)
Добрый вечер, посоветуйте способ или модуль для переноса нод из друпал 7 на друпал 6
Скажите, удастся ли экспортировать помимо типов материалов еще и их настройки отображения?
Если напишите свой MigrateDestination, то удастся что угодно.
Здравствуйте, помогите с такой ситуацией. Переезжаю на Drupal 8. Миграция прошла успешно. Отключил модули Migrate Migrate Drupal Migrate Drupal UI (больше не нужны). Но в базе данных осталось много таблиц migrate_map_... . Можно ли их удалить? И почему они не удалились автоматически?
Уважаемый xandeadx!
У меня ситуация такая:
Имеется xml
Если убрать атрибут xmlns, то импорт проходит отлично. Если оставить, то ноды создаются пустые. Ошибок нет никаких.
Я так понимаю что xmlns - пространство имён.
Пробовал делать так:
Не помогает. Вы не в курсе как это исправить?
Задал вопрос на drupal.org, ответов нет (
Не в курсе
Может есть какая новая информация на сегодняшний день по миграции с 7 на 9?
Один сайт из 60 страниц ручками переношу, а вот второй конечно хотелось бы упростить.
@Игорь у Никлана есть подробная дока, но сразу предупреждаю, что процесс ни разу не простой.
Добавить комментарий