Изменение типа контента узла

8

В Drupal 7 я могу легко переключать тип содержимого узла с помощью Node convert . Однако Node Convert не был портирован на Drupal 8, и, похоже, не слишком много энтузиазма по поводу порта.

Если у меня есть два типа контента с одинаковыми полями, как я могу преобразовать узел из типа контента в другой, в Drupal 8? Какой код я должен использовать для Drupal 8, что эквивалентно следующему коду Drupal 7, используемому модулем Node convert ? (См. node_convert_node_convert()В node_convert.util.inc .)

  // $nid, $destination_node_type, $source_fields, $destination_fields,
  // $no_fields_flag, and $hook_options are the parameters passed to the function.

  $node = node_load($nid);
  if ($node == FALSE) {
    return FALSE;
  }

  // Change the node type in the DB
  db_update('node')->fields(array('type' => $destination_node_type))->condition('nid', $nid)->execute();

  // If there are fields that can be converted
  if ($no_fields_flag == FALSE) {

    // Conversion process for each field
    $re_save_body_field = FALSE;

    // Use node revisions to extract all field revision in node_convert_field_convert
    $node_revisions = node_revision_list($node);

    foreach ($source_fields as $key => $field) {
      $replaced_body = node_convert_field_convert($node, $field, $destination_fields[$key], $destination_node_type, $node_revisions);
      if ($replaced_body == REPLACE_BODY) {
        $re_save_body_field = TRUE;
      }
    }
    // If something was appended to the body, or replaced the body, we update body field.
    if ($re_save_body_field == TRUE) {
      $field_body = field_info_fields();
      $field_body = $field_body['body'];
      $field_ids = array($field_body['id'] => $field_body['id']);
      module_invoke($field_body['storage']['module'], 'field_storage_write', 'node', $node, FIELD_STORAGE_UPDATE, $field_ids);
    }
  }

  // Omissis.

  // Clear the node cache, so we have the latest information when saving the
  // node.
  $controller = entity_get_controller('node');
  /* @var $controller DrupalEntityControllerInterface */
  $controller->resetCache(array($node->nid));
  cache_clear_all('field:node:' . $node->nid, 'cache_field');

 

node_convert_field_convert() содержит следующий код

  // &$node, $source_field, $destination_field, $destination_node_type,
  // and $node_revisions are the parameters passed to node_convert_field_convert().

  $field_info_source = field_info_fields(); // Get source field information
  $field_info_source = $field_info_source[$source_field];
  $db_info_source = $field_info_source['storage']; // Get DB specific source field information

  if ($destination_field == 'discard') {
    // Delete node info in the separate field table
    node_convert_invoke_field_storage_delete($field_info_source, $db_info_source, $node);
    return NULL;
  }

  $field_info_destination = array();
  $db_info_destination = array();
  if (!in_array($destination_field, array('discard', APPEND_TO_BODY, REPLACE_BODY))) {
    $field_info_destination = field_info_fields($destination_field); // Get destination field information
    $field_info_destination = $field_info_destination[$destination_field]; // Get destination field information
    $db_info_destination = $field_info_destination['storage']; // Get DB specific destination field information
  }

  // We save each field value from the DB for transfer. (this only applies to the current revision of the field)
  $source_values = field_get_items('node', $node, $source_field);

  if (count($node_revisions) > 1 && !in_array($destination_field, array(APPEND_TO_BODY, REPLACE_BODY))) {
    // Get all field revisions for current node
    $field_revision_values = array();
    $field_revision_source_table = current(array_keys($db_info_source['details']['sql']['FIELD_LOAD_REVISION']));
    $field_revision_destination_table = current(array_keys($db_info_destination['details']['sql']['FIELD_LOAD_REVISION']));

    $source_columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'delta', 'language');
    foreach ($field_info_source['columns'] as $column => $attributes) {
      $source_columns[] = _field_sql_storage_columnname($source_field, $column);
    }

    $revision_query = db_select($field_revision_source_table, 'r', array('fetch' => PDO::FETCH_ASSOC))
      ->condition('entity_type', 'node')
      ->condition('bundle', $node->type)
      ->condition('entity_id', $node->nid)
      ->condition('revision_id', $node->vid, '<>')
      ->fields('r', $source_columns)->execute();

    // Change the bundle to the destination type of the node
    foreach ($revision_query as $row) {
      $row['bundle'] = $destination_node_type;
      $field_revision_values[] = $row;
    }

    // Remove all field revisions for current field in DB
    node_convert_invoke_field_storage_delete($field_info_source, $db_info_source, $node);

    // Reinsert the field revisions in the destination field revision table
    $query = db_insert($field_revision_destination_table);
    $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'delta', 'language');
    foreach ($field_info_destination['columns'] as $column => $attributes) {
      $columns[] = _field_sql_storage_columnname($destination_field, $column);
    }
    $query->fields($columns);
    foreach ($field_revision_values as $row) {
      $query->values(array_values($row));
    }
    $query->execute();

  }
  else {
    // After getting the source field values, we delete the values stored in the DB (this deletes values for all field revisions)
    node_convert_invoke_field_storage_delete($field_info_source, $db_info_source, $node);
  }

  // The source field value should be appended to the body or replaced.
  if ($destination_field == APPEND_TO_BODY || $destination_field == REPLACE_BODY) {
    static $node_body = '';
    //static $node_teaser = '';

    // We try to get the node body from a static variable, which means we did some body manipulations, otherwise load it.
    if (empty($node_body)) {
      $node_body_field = field_get_items('node', $node, 'body');
      $node_body = $node_body_field[0]['value'];
      //$node_teaser = $node_body_field[0]['summary'];
    }

    // Double check we have values in the field.
    if (is_array($source_values)) {
      // Get the field value.
      $field_value = node_convert_format_field_value($node, $field_info_source, TRUE);

      if ($destination_field == APPEND_TO_BODY) {
        $node_body = $node_body . "\n" . $field_value;
        //$node_teaser = $node_teaser . "\n" . $field_value['value'];
      }
      elseif ($destination_field == REPLACE_BODY) {
        $node_body = $field_value;
        //$node_teaser = $field_value['value'];
      }
      $lang_code = field_language('node', $node, $source_field);
      $node->body[$lang_code][0]['value'] = $node_body;
      //$node->body[$lang_code][0]['summary'] = $node_teaser;
    }

    return REPLACE_BODY;
  }

  // We put each field value back into the DB
  // To do it we first get the id of the field, then we find its language code from the source value
  // We add $source_values into the node object, and invoke field_storage write
  $field_ids = array($field_info_destination['id'] => $field_info_destination['id']);
  $lang_code = field_language('node', $node, $source_field);

  // Make sure that we actually have values in the source field
  if ($source_values !== FALSE) {
    $node->{$destination_field}[$lang_code] = $source_values;
  }
  else {
    $node->{$destination_field} = array();
  }

  // Give possibility to fields to pre-process their data
  // (e.g., Link module transforms attribute array into a serialized array before insertion)
  field_attach_presave('node', $node);
  // For some reason link_field_presave doesn't exist anymore, so we have to call it the processing function used inside manually.
  if ($field_info_destination['type'] == 'link_field') {
    $instances = field_info_instances('node', $destination_node_type);
    link_field_update('node', $node, $field_info_destination, $instances[$destination_field], $lang_code, $node->{$destination_field}[$lang_code]);
  }
Screenack
источник
1
Вы в основном разместили здесь большую часть модуля и попросили сделать для вас преобразование. Почему бы не попробовать версию Drupal 8, а затем опубликовать более конкретные вопросы здесь, когда вы застряли?
Бенджи
Кто-то еще предложил опубликовать код из модуля D7, улучшив мой оригинальный вопрос. Я хотел бы попробовать это, но я ограничен тем, что я не программист.
Screenack
2
Если честно, кто-то может встретиться и портировать его однажды, я вижу, вы прокомментировали проблему Drupal 8, которая может заинтересовать вас. В противном случае вы могли бы заплатить кому-то, чтобы конвертировать его, я не думаю, что это займет очень много времени.
Бенджи

Ответы:

2

Прошло некоторое время, и хорошая новость в том, что теперь есть модуль convert_bundles для d8.

Это альфа, но я смог использовать его для преобразования сущностей на сайте разработчика.

dnebrich
источник
1

Йоахим Норейко только что опубликовал сообщение в блоге об изменении типа узла . Вам нужно будет обновить следующие таблицы:

  • базовая таблица сущностей
  • таблица данных объекта
  • таблица данных редакции объекта
  • таблица данных каждого поля
  • таблица изменений данных каждого поля

Пост содержит полные инструкции и фрагменты кода, просто следуйте им шаг за шагом.

Вим Мострей
источник
1

Вот решение для преобразования узлов статьи в тип блога. Я попробовал Convert Bundles, предложенный в другом ответе, но не смог отфильтровать, какие узлы конвертировать. Благодаря этому вы можете добавить в запрос дополнительные условия, такие как значение термина таксономии.

$query = \Drupal::entityQuery('node')
  ->condition('type', 'article')
$results = $query->execute();

foreach ($results as $nid) {
  $node = \Drupal\node\Entity\Node::load($nid);
  $node->set('type', 'blog');
  $node->save();
}
mortona42
источник
Это самый простой и лучший способ преобразовать тип узла
ржи