Como migrar entidades de arquivo para entidades de mídia?

10

Estou usando o módulo Migrate para uma migração D7 para D8 e estou escrevendo toda a migração manualmente no código (em vez de usar o módulo de migração D7 interno, pois queria um controle mais granual na migração).

Eu tenho a seguinte estrutura: o site D7 tem um campo de imagem onde as imagens são armazenadas como entidades de arquivo. No site D8, o campo de imagem é uma referência de entidade para uma entidade de Mídia (e a entidade de Mídia, por sua vez, possui um campo de Imagem).

Originalmente, eu tinha o seguinte para minha migração de imagens:

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

No arquivo de migração do nó do artigo, eu tinha o seguinte:

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

mas percebi que isso não funcionaria. O target_id proveniente da migração de image_files era realmente um ID de entidade de arquivo, não um ID de entidade de mídia. No mundo ideal, eu gostaria de encontrar uma maneira de criar uma terceira migração, que criaria essa etapa intermediária, e migrar entidades de arquivo para entidades de mídia e, em seguida, mapear essa migração para a migração de artigos. No entanto, não consigo descobrir uma boa maneira de fazer isso.

O plano B será simplesmente criar um plug-in de processo para a migração de imagens, que criará manualmente entidades de arquivo, anexará-as a entidades de mídia e passará essa migração para o Articles (isso remove a etapa intermediária). Isso significaria, porém, que, embora as entidades de Mídia possam ser revertidas, as Entidades de Arquivo não podem.

user1015214
fonte

Respostas:

4

Acabei optando por fazê-lo um pouco diferente - eu crio uma importação de arquivo regular, defino essa migração como a origem do campo de referência da minha entidade de mídia e apliquei um segundo plug-in de processo 'MediaGenerate' para converter o FID na nova mídia 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
fonte
11
Qual é a configuração destinationField?
dba
Ok, eu descobri por mim mesmo, é o campo para o ativo no tipo de mídia, para a imagem que é isso field_media_image.
dba
Como você lida com os atributos alt / title do arquivo?
MPP
Testado e funciona bem, no entanto, você provavelmente precisará usar o plug-in "migration_lookup" porque o plug-in "migration" está obsoleto e não funcionou nas minhas versões mais recentes. A seguir, trabalhei para mim importar imagens do usuário: plugin: migration_lookup migration: my_file_migration source: picture Além disso, se você migrar entidades sem bundles (como fotos do usuário), provavelmente precisará do patch a partir daqui: drupal.org/project/migrate_plus/issues / 2787219 , caso contrário, você receberá um erro "O plug-in entity_lookup requer uma chave de valor, nenhuma localizada." na migração.
Mirsoft
Alguém poderia explicar como $ entityId é encontrado nisso?
dibs
2

Apreciei bastante a resposta aceita, mas ela já tinha algumas definições obsoletas e não suportava a publicação de propriedades de imagem alt e title. Assim, aprimorei-o um pouco para dar suporte a isso e funcionar sem problemas com o Drupal 8.6.x. mais recente. Aqui está o código do MediaGenerate.php (a sintaxe apropriada do Yaml está dentro do comentário do documento):

<?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
fonte
2

Como Mídia é um tipo de entidade, você deve criar sua própria migração. Você pode gerar uma nova fonte a partir da tabela de arquivos. Aqui está um exemplo

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

Depois, migration_lookupvocê pode mapear os campos como este.

field_d8_media_image/0/target_id:
  plugin: migration_lookup
  migration: my_media_image
  source: field_d7_image/0/fid
fabianfiorotto
fonte
0

Se você deseja migrar arquivos no Drupal 8 para entidades de mídia, pode usar este módulo: https://www.drupal.org/project/migrate_file_to_media

Possui um script drush, que cria automaticamente os campos de referência de mídia. Além disso, ele detecta imagens duplicadas usando um hash binário. E suporta traduções.

Brainski
fonte
11
Esse módulo resolve apenas a migração entre as versões do D8 por padrão. A questão é mais parecida com a migração do D7 para o D8, para que o módulo não possa ser usado com facilidade (um plug-in de origem adicional para o MediaEntityGenerator.php que lê dados de arquivos anexados no D7 provavelmente precisará ser criado). Há também uma diferença fundamental: o módulo migrate_file_to_media converte apenas arquivos anexados a certa entidade (= tipo de entidade e pacote configurável são necessários na etapa 1), enquanto a solução aceita não possui esse requisito e primeiro migra todas as entidades de arquivo do (D7) fonte.
Mirsoft