Как перенести файловые объекты в медиа-объекты?

10

Я использую модуль Migrate для миграции с D7 на D8 и пишу всю миграцию вручную в коде (вместо того, чтобы использовать встроенный модуль миграции D7, так как я хотел более детального управления миграцией).

У меня есть следующая структура: сайт D7 имеет поле изображения, где изображения хранятся в виде файловых объектов. На сайте D8 поле изображения является ссылкой на объект Media (а объект Media, в свою очередь, имеет поле Image).

Первоначально у меня было следующее для миграции изображений:

id: image_files

source:
  plugin: legacy_images
  constants:
    source_base_path: http://example.com/

destination:
  plugin: 'entity:file'

process:
  fid: fid
  filename: filename
  source_full_path:
    -
      plugin: concat
      delimiter: /
      source:
    -     constants/source_base_path
    -     uri
    -
      plugin: urlencode
  uri:
    plugin: file_copy
    source:
      - '@source_full_path'
      - uri
  filemime: filemime
  status: status

Внутри моего файла миграции узла статьи у меня было следующее:

'field_article_image/target_id':
plugin: migration
migration: image_files
source: field_article_image 

но я понял, что это не сработает. Идентификатор target_id, полученный в результате миграции image_files, на самом деле был идентификатором объекта File File ID, а не идентификатором объекта Media. В идеальном мире я хотел бы найти способ создать третью миграцию, которая создала бы этот средний шаг, и перенести файловые сущности в медиа-сущности, а затем сопоставить эту миграцию с миграцией статей. Тем не менее, я не могу найти хороший способ сделать это.

План B будет состоять в том, чтобы просто создать плагин процесса для миграции изображений, который будет вручную создавать файловые объекты, прикреплять их к медиа-объектам и передавать эту миграцию в Статьи (это удаляет средний шаг). Это будет означать, однако, что, хотя сущности Media можно откатить, объекты File не могут.

user1015214
источник

Ответы:

4

В итоге я решил сделать это немного по-другому - я создаю обычный импорт файлов, устанавливаю эту миграцию в качестве источника для моего ссылочного поля медиа-объекта, а затем применил второй плагин процесса 'MediaGenerate', чтобы преобразовать FID в новый медиа target_id

<?php

namespace Drupal\my_migration\Plugin\migrate\process;

use Drupal\media_entity\Entity\Media;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\MigrateException;
use Drupal\migrate\Row;
use Drupal\migrate_plus\Plugin\migrate\process\EntityGenerate;

/**
 * Generate a media entity with specified metadata.
 *
 * This plugin is to be used by migrations which have media entity reference
 * fields.
 *
 * Available configuration keys:
 * - destinationField: the name of the file field on the media entity.
 *
 * @code
 * process:
 *   'field_files/target_id':
 *     -
 *       plugin: migration
 *       source: files
 *     -
 *       plugin: media_generate
 *       destinationField: image
 *
 * @endcode
 *
 * @MigrateProcessPlugin(
 *   id = "media_generate"
 * )
 */
class MediaGenerate extends EntityGenerate {

/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrateExecutable, Row $row, $destinationProperty) {
if (!isset($this->configuration['destinationField'])) {
  throw new MigrateException('Destination field must be set.');
}
// First load the target_id of the file referenced via the migration.
/* @var /Drupal/file/entity/File $file */
$file = $this->entityManager->getStorage('file')->load($value);

if (empty($file)) {
  throw new MigrateException('Referenced file does not exist');
}

// Creates a media entity if the lookup determines it doesn't exist.
$fileName = $file->label();
if (!($entityId = parent::transform($fileName, $migrateExecutable, $row, $destinationProperty))) {
  return NULL;
}
$entity = Media::load($entityId);

$fileId = $file->id();
$entity->{$this->configuration['destinationField']}->setValue($fileId);
$entity->save();

return $entityId;
}

}
user1015214
источник
1
Что такое конфигурация destinationField?
ДБА
Хорошо, я понял это сам, это поле для актива в типе носителя, для изображения это field_media_image.
ДБА
Как вы обрабатываете атрибуты файла alt / title?
mpp
Протестировано и работает хорошо, однако вам, вероятно, понадобится использовать плагин «igration_lookup », потому что плагин« миграция »устарел и уже не работал в моих последних версиях. Следующее сработало для меня, чтобы импортировать пользовательские изображения: плагин :igration_lookup миграция: my_file_migration источник: картинка Также, если вы переносите объекты без пакетов (например, пользовательских изображений), вам, вероятно, понадобится патч отсюда: drupal.org/project/migrate_plus/issues / 2787219 , в противном случае вы получите сообщение об ошибке «Для плагина entity_lookup требуется значение_ключа, ни один из них не найден». на миграцию.
Мирсофт
Может кто-нибудь объяснить, как $ entityId находится в этом?
DIBS
2

Я высоко оценил принятый ответ, однако он уже имел некоторые устаревшие определения и не поддерживал публикацию свойств изображения alt и title. Таким образом, я немного улучшил его, чтобы поддерживать это и работать гладко с последним Drupal 8.6.x. Вот код MediaGenerate.php (соответствующий синтаксис Yaml находится внутри комментария к документу):

<?php

namespace Drupal\my_migration\Plugin\migrate\process;

use Drupal\media\Entity\Media;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\MigrateException;
use Drupal\migrate\Row;
use Drupal\migrate_plus\Plugin\migrate\process\EntityGenerate;

/**
 * Generate a media entity with specified metadata.
 *
 * This plugin is to be used by migrations which have media entity reference
 * fields.
 *
 * Available configuration keys:
 * - destinationField: the name of the file field on the media entity.
 *
 * @code
 * process:
 *   'field_files/target_id':
 *     -
 *       plugin: migration_lookup
 *       migration: my_file_migration
 *       source: field_image/0/fid
 *     -
 *       plugin: media_generate
 *       destinationField: image
 *       imageAltSource: field_image/0/alt
 *       imageTitleSource: field_image/0/title
 *
 * @endcode
 *
 * If image_alt_source and/or image_title_source configuration parameters
 * are provided, alt and/or title image properties will be fetched from provided
 * source fields (if available) and pushed into media entity
 *
 * @MigrateProcessPlugin(
 *   id = "media_generate"
 * )
 */
class MediaGenerate extends EntityGenerate {

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrateExecutable, Row $row, $destinationProperty) {
    if (!isset($this->configuration['destinationField'])) {
      throw new MigrateException('Destination field must be set.');
    }

    // First load the target_id of the file referenced via the migration.
    /* @var /Drupal/file/entity/File $file */
    $file = $this->entityManager->getStorage('file')->load($value);

    if (empty($file)) {
      throw new MigrateException('Referenced file does not exist');
    }

    // Creates a media entity if the lookup determines it doesn't exist.
    $fileName = $file->label();
    if (!($entityId = parent::transform($fileName, $migrateExecutable, $row, $destinationProperty))) {
      return NULL;
    }

    $entity = Media::load($entityId);

    $fileId = $file->id();

    $destinationFieldValues = $entity->{$this->configuration['destinationField']}->getValue();
    $destinationFieldValues[0]['target_id'] = $fileId;

    $this->insertPropertyIntoDestinationField($destinationFieldValues, $row, 'alt', 'imageAltSource');
    $this->insertPropertyIntoDestinationField($destinationFieldValues, $row, 'title', 'imageTitleSource');

    $entity->{$this->configuration['destinationField']}->setValue($destinationFieldValues);
    $entity->save();

    return $entityId;
  }

  protected function insertPropertyIntoDestinationField(array &$destinationFieldValues, Row $row, $propertyKey, $configurationKey) {
    // Set alt and title into media entity if not empty
    if (isset($this->configuration[$configurationKey])) {
      $propertyValue = $row->getSourceProperty($this->configuration[$configurationKey]);
      if (!empty($propertyValue)) {
        $destinationFieldValues[0][$propertyKey] = $propertyValue;
      }
    }
  }
}
Mirsoft
источник
2

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

https://gist.github.com/jibran/8e7cd2319e873858dd49a272227a4fd2

Затем migration_lookupвы можете сопоставить поля, как это.

field_d8_media_image/0/target_id:
  plugin: migration_lookup
  migration: my_media_image
  source: field_d7_image/0/fid
fabianfiorotto
источник
0

Если вы хотите перенести файлы в Drupal 8 на медиа-объекты, вы можете использовать этот модуль: https://www.drupal.org/project/migrate_file_to_media

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

Brainski
источник
1
Этот модуль только решает миграцию между версиями D8 по умолчанию. Вопрос больше похож на миграцию с D7 на D8, так что модуль не может быть легко использован (вероятно, потребуется создать дополнительный плагин к MediaEntityGenerator.php, который будет считывать данные из вложенных файлов в D7). Существует также одно принципиальное отличие: модуль migrate_file_to_media преобразует только файлы, прикрепленные к определенному объекту (= entity_type и bundle требуются на шаге 1), в то время как в принятом решении нет этого требования, и он сначала переносит все файловые объекты из (D7) источник.
Мирсофт