Migrate: импорт товаров с автоматическим созданием многоуровневого каталога


64

Есть файл для импорта товаров (нод), в котором категория товара указана в виде списка названий категорий и подкатегорий. Для миграции таких терминов из коробки можно использовать следующую конструкцию...

Есть файл для импорта товаров (нод), в котором категория товара указана в виде списка названий категорий и подкатегорий. Например:

Для миграции таких терминов из коробки можно использовать следующую конструкцию (миграция данных в multi-value поля):

$this->addFieldMapping('taxonomy_catalog', 'catalog')->separator(',');
//сообщим Migrate, что мы используем имена терминов, а не tid
$this->addFieldMapping('taxonomy_catalog:source_type')->defaultValue('name');
//если термин не найден по имени, разрешим автоматическое создание термина
$this->addFieldMapping('taxonomy_catalog:create_term')->defaultValue(TRUE);

Во время импорта migrate осуществляет поиск термина по имени, если его нет в словаре, то он автоматически создается. 

Плюсы: 

  • решение из коробки; 

Минусы: 

  • нет иерархии терминов; 
  • в словаре отсутствуют термины с одинаковыми именами;

Конечно, мы можем на основе нашего файла для импорта нод сделать файл со списком терминов, отдельно импортировать термины и только потом ноды. Если каталог изменится, эти манипуляции придется повторить. 

Мы сделаем немного по-другому....

public function __construct($arguments) {
  ...
    $this->addFieldMapping('taxonomy_catalog', 'catalog');
    $this->addFieldMapping('taxonomy_catalog:source_type')->defaultValue('tid');
    $this->addFieldMapping('taxonomy_catalog:create_term')->defaultValue(TRUE);
}
 
public function prepareRow($row) {
  ...
    if (isset($row->catalog) && !empty($row->catalog)) {
//для нормальной работы нам нужно знать vid словаря таксономии, в который будут импортироваться термины.
   $vocabulary = taxonomy_vocabulary_machine_name_load('catalog');
   $vid = $vocabulary->vid;
//Если Вы не хотите постоянно дергать ​функцию taxonomy_vocabulary_machine_name_load,
//можете вручную указать номер нужного словаря
// $vid = 2;

      $row->catalog = _migrate_taxonomy_term_tree($row->catalog, $vid);
    }
}
И напишем функцию, которая на основе строки с терминами, разделенными запятой, будет возвращать массив с tid.
function _migrate_taxonomy_term_tree($namestxt, $vid) {
  $names = explode(',', $namestxt);
  $tids = array();
  foreach ($names as $depth => $name) {
  //предварительно очистим заголовок термина
    $name = trim(check_plain($name));
  //определим родителя
    $parent = ($depth > 0) ? $tids[$depth - 1] : 0;

  //пробуем найти нужный tid 
    $query = db_select('taxonomy_term_data', 't');
    $query->innerJoin('taxonomy_term_hierarchy', 'th', 't.tid = th.tid');
    $query->fields('t', array('tid'));
    $query->condition('t.vid', $vid);
    $query->condition('t.name', $name);
    $query->condition('th.parent', $parent);
    $tid = $query->execute()->fetchField();

    if ($tid) {
      //термин уже в БД
      $tids[$depth] = $tid;
    }
    else {
      //нужно создавать термин
      $term = array(
        'vid' => $vid,
        'name' => $name,
        'parent' => $parent,
      );
      $term = (object) $term;
      taxonomy_term_save($term);
      if ($term->tid) {
        $tids[$depth] = $term->tid;
      }
      else {
        $tids[$depth] = 0;
        drupal_set_message(t('Query not successful.'), 'error');
      }
    }
  }

//на всякий случай проверим массив и удалим нулевые термины
  foreach ($tids as $key => $tid) {
    if($tid == 0){
      unset($tids[$key]);
    }
  }
  return $tids;
}

К данному решению можно прикрутить кеширование, что бы уменьшить количество запросов к БД. Но мне пока лень этим заниматься :-)

Вот вариант работы с кешированием:
function _migrate_taxonomy_term_tree($namestxt, $vid) {
  $names = explode(',', $namestxt);
  $namesmd5 = md5($vid . '_' . $namestxt);
  $tids = array();

  if ($cache = cache_get('migrate_term_tree_' . $namesmd5)) {
    $tids = explode(',', $cache->data);
  }else{

  foreach ($names as $depth => $name) {
    $name = trim(check_plain($name));

    $parent = ($depth > 0) ? $tids[$depth - 1] : 0;

    $query = db_select('taxonomy_term_data', 't');
    $query->innerJoin('taxonomy_term_hierarchy', 'th', 't.tid = th.tid');
    $query->fields('t', array('tid'));
    $query->condition('t.vid', $vid);
    $query->condition('t.name', $name);
    $query->condition('th.parent', $parent);
    $tid = $query->execute()->fetchField();

    if ($tid) {
      //термин уже в БД
      $tids[$depth] = $tid;
    }
    else {
      //нужно создавать термин
      $term = array(
        'vid' => $vid,
        'name' => $name,
        'parent' => $parent,
      );
      $term = (object) $term;
      taxonomy_term_save($term);
      if ($term->tid) {
        $tids[$depth] = $term->tid;
      }
      else {
        $tids[$depth] = 0;
        drupal_set_message(t('Query not successful.'), 'error');
      }
    }
  }

  foreach ($tids as $key => $tid) {
    if($tid == 0){
      unset($tids[$key]);
    }
  }

    cache_set('migrate_term_tree_' . $namesmd5, implode(',', $tids), 'cache', time() + 3600);
  }
  return $tids;
}

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

Drupal Drupal 7 — Статьи проmigrate
Добавить комментарий
Может быть интересно

Данный скрипт поможет пересохранить файлы Excel в csv. Может быть полезно перед отправкой прайсов на хостинг для дальнейшей обработки

6
Модуль Migrate это фреймворк для миграции (импорта) данных в Drupal из любых источников.
1

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

2

В операционной системе Windows, как и в других операционных системах, интерактивные (набираемые с клавиатуры и сразу же выполняемые) команды выполняются с помощью так называемого командного интерпретатора, иначе называемого командным процессором или оболочкой командной строки (command shell).

3
Снова возвращаемся к migrate. Довольно удобный фреймворк для импорта данных в Друпал. Один из распространенных форматов источника для импорта - CSV. Поддерживается migrate из коробки. Описание и примеры работы с классом MigrateSourceCSV можно найти на drupal.org.
2