migrate

Migrate: Импорт материалов. Как же ты все-таки работаешь?


75

В данной статье будет теория про механизм, который использует модуль migrate при импорте материалов в Друпал из различных источников.

Думаю, многие, как и я, в своей практике используют довольно стандартный алгоритм при импорте:

  1. Получили массив с данными для импорта очередного материала
  2. Сделали поиск среди уже существующих материалов по ключевому полю (Заголовок, Артикул или что-то другое)
  3. Если материал уже присутствует, то вызываем node_load и подгружаем ноду для её дальнейшего редактирования.
  4. Если материала нет, но создаем новый объект node
  5. Вносим изменения в объект node согласно данным из источника
  6. node_save

Migrate разделяет два возможных варианта (когда нода уже существует и когда нет) на два различных режима миграции. За переключение режимов отвечает свойство systemOfRecord. Допустимые значения: Migration::SOURCE (по умолчанию) и Migration::DESTINATION.

Migration::SOURCE

Данный режим миграции установлен по умолчанию. 

Интересно то, что при данном режиме не происходит вызов node_load() для существующих материалов. А объект $node формируется каждый раз заново на основе тех полей, которые есть в источнике. Не секрет, что migrate хранит таблицу соответствий для ключей source_id=>destination_id. Так, вот, если для текущего ключевого поля в источнике уже есть идентификатор материала, то он будет присвоет объекту ноды и материал будет перезаписан. Важно понимать, что при таком подходе migrate не интересует состояние текущей ноды. Он просто получает набор данных, на их основе формирует ноду и сохраняет ее.

 

Особенности Migration::SOURCE

  • Идеально подходит для случая, когда в источнике хранится весь набор полей ноды.
  • track_changes
  • Можно попробовать применить для обновления отдельных полей материала, но тут нужно тестировать на конкретном проекте. Например, поля с изображениями пропадут из ноды, если они будут отсутствовать в источнике.
  • Можно добавлять к материалу дополнительные поля, которые не учавствуют в импорте, например, примечания к материалу, или набор чекбоксов с опциями для конкретной ноды. Данные в таких полях сохранят свои значения неизменными. Но будьте внимательны, не все типы полей подходят. Тестировал на  textfield и checkbox.

Кстати, опция track_changes отлично справляется со своей задачей при таком методе. В момент создания новой ноды, вместе с сохранением записи source_id=>destination_id, происходит запись hash от набора данных в строке источника. При  следующем импорте, при включенной опции  track_changes, будет получен новый hash от текущих данных в источнике. Если он будет такой-же, как и раньше, то элемент будет пропущен.

Migration::DESTINATION

Обновление существующих материалов. Данный режим позволяет обновлять текущие материалы. 

В таком режиме в качестве таблицы соответствий source_id=>destination_id нужно использовать результат от миграции первого типа (MIgration::SOURCE), т.к. данный режим не умеет создавать новые ноды. Если для текущего ключевого поля в источнике не будет найден идентификатор существующего материала, то данная запись будет пропущена. Такж, если не удается получить объект ноды через node_load (например, материал был удален), то запись будет пропущена. Принцип работы прост - после загрузки ноды будут заменены значения тех полей, что присутствуют в источнике (конечно же, если для них будет настроено соответствие в классе миграции (маппинг полей)).

Приведу небольшой пример, как выглядит простейший класс миграции для второго режима. Представим, что у нас уже есть миграция с первым режимом ProductCSV. Тогда создадим миграцию для обновления поля с ценой у существующих товаров.

class ProductsMigrationUpdate extends Migration {
  public function __construct($arguments) {
    parent::__construct($arguments);

//Указываем зависимость от миграции ProductCSV
    $this->dependencies = array(
      'ProductCSV',
    );
//Меняем режим работы
    $this->systemOfRecord = Migration::DESTINATION;

    $columns = array();
    $options = array(
      'header_rows'   => 1,
    );
    $sheet_name = 'update';

    $this->source = new MigrateSourceSpreadsheet(DRUPAL_ROOT . '/update.xls', $sheet_name, $columns, $options);

// Key schema
    $source_key_schema = array(
      'model' => array(
        'type'        => 'varchar',
        'length'      => 30,
        'not null'    => TRUE,
        'description' => 'Source ID',
      )
    );

    $this->map = new MigrateSQLMap($this->machineName, $source_key_schema, MigrateDestinationNode::getKeySchema());
// Destination
    $this->destination = new MigrateDestinationNode('product');

// Key schema
// Забираем данные о ключах из результатов миграции ProductCSV
    $this->addFieldMapping('nid', 'model')->sourceMigration('ProductCSV');

    //Mapping
    $this->addFieldMapping('status')->defaultValue(TRUE);
    $this->addFieldMapping('uid')->defaultValue(1);
    $this->addFieldMapping('sell_price', 'price')->defaultValue(0);
  }
}

Особенности

Подходит для обновления определенных полей.
Можно создать миграцию с минимальным набором полей (ключевое поле, цена), а дальше, в процессе работы через migrateUI прямо из админки мапить поля в зависимоти от набора в источнике.

P.S. Вас никто не ограничивает в свободе действий! За импорт материалов отвечает класс MigrateDestinationNode. У него есть интересный метод import. Именно он и реализует работу данных режимов миграции. Вы можете в своем модуле унаследовать данный класс и адаптировать механизм под свои  замудрёные задачки.

Актуально для:
migrate7.x-2.8

Drupal Drupal 7 — Статьи проmigrate
Добавить комментарий
Может быть интересно
Модуль Migrate это фреймворк для миграции (импорта) данных в Drupal из любых источников.
1
Снова возвращаемся к migrate. Довольно удобный фреймворк для импорта данных в Друпал. Один из распространенных форматов источника для импорта - CSV. Поддерживается migrate из коробки. Описание и примеры работы с классом MigrateSourceCSV можно найти на drupal.org.
2
Допустим, есть словарь с терминами (недавно с ними работал, поэтому с них и начну). У терминов есть дополнительные поля. Мы хотим получить список терминов, у которых значение поля имеет определенное значение.
1
Задача: разрешить пользователю во время оформления заказа выбрать вариант предоплаты (50% от стоимости заказа). Например, при продаже билетов на мероприятие. Остальная оплата будет осуществляться на месте самого мероприятия...
2
По умолчанию в drupal commerce через правила Вы можете работать с полем цена у сущности commerce_product. А вот если Вам необходимо достучаться до поля цена у заказа, то тут будут проблемы. Покажу, как научить правила работать с ценой у заказа.
2