В данной статье будет теория про механизм, который использует модуль migrate при импорте материалов в Друпал из различных источников. Причина написания данной статьи очень проста - я был удивлён... :-)
Думаю, многие, как и я, в своей практике используют довольно стандартный алгоритм при импорте:
- Получили массив с данными для импорта очередного материала
- Сделали поиск среди уже существующих материалов по ключевому полю (Заголовок, Артикул или что-то другое)
- Если материал уже присутствует, то вызываем node_load и подгружаем ноду для её дальнейшего редактирования.
- Если материала нет, но создаем новый объект node
- Вносим изменения в объект node согласно данным из источника
- node_save
Migrate разделяет два возможных варианта (когда нода уже существует и когда нет) на два различных режима миграции. За переключение режимов отвечает свойство systemOfRecord. Допустимые значения: Migration::SOURCE (по умолчанию) и Migration::DESTINATION.
Migration::SOURCE
Данный режим миграции установлен по умолчанию.
Интересно то, что при данном режиме не происходит вызов node_load() для существующих материалов. А объект $node формируется каждый раз заново на основе тех полей, которые есть в источнике. Не секрет, что migrate хранит таблицу соответствий для ключей source_id=>destination_id. Так, вот, если для текущего ключевого поля в источнике уже есть идентификатор материала, то он будет присвоет объекту ноды и материал будет перезаписан. Важно понимать, что при таком подходе migrate не интересует состояние текущей ноды. Он просто получает набор данных, на их основе формирует ноду и сохраняет ее.
Особенности
- Идеально подходит для случая, когда в источнике хранится весь набор полей ноды.
- 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
Комментарии
Добавить комментарий