Comment migrer des entités de fichier vers des entités multimédias?

10

J'utilise le module Migrate pour une migration D7 vers D8 et j'écris toute la migration manuellement dans le code (plutôt que d'utiliser le module de migration D7 intégré, car je voulais un contrôle plus granulaire de la migration.)

J'ai la structure suivante: le site D7 a un champ d'image où les images sont stockées en tant qu'entités de fichier. Sur le site D8, le champ image est une référence d'entité à une entité média (et l'entité média à son tour a un champ image).

À l'origine, j'avais les éléments suivants pour ma migration d'images:

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

Dans mon fichier de migration de nœud d'article, j'avais les éléments suivants:

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

mais j'ai réalisé que cela ne fonctionnerait pas. L'ID cible provenant de la migration des fichiers image était en fait des ID d'entité de fichier, et non des ID d'entité multimédia. Dans le monde idéal, j'aimerais trouver un moyen de créer une troisième migration, qui créerait cette étape intermédiaire, et migrerait les entités de fichier dans les entités multimédias, puis mapperait cette migration vers la migration des articles. Cependant, je ne peux pas trouver une bonne façon de procéder.

Le plan B consistera simplement à créer un plug-in de processus pour la migration des images, qui créera manuellement des entités de fichier, les joindra aux entités multimédias et passera cette migration aux articles (cela supprime l'étape intermédiaire). Cela signifierait, cependant, que même si les entités multimédias peuvent être annulées, les entités de fichiers ne le peuvent pas.

user1015214
la source

Réponses:

4

J'ai fini par choisir de le faire légèrement différemment - je crée une importation de fichier régulière, définit cette migration comme source pour mon champ de référence d'entité multimédia, puis applique un deuxième plugin de processus 'MediaGenerate' pour traduire le FID en nouveau 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
la source
1
Quelle est la configuration de destinationField?
dba
Ok, je l'ai compris moi-même, c'est le champ de l'actif dans le type de support, pour l'image c'est field_media_image.
dba
Comment gérez-vous les attributs de fichier alt / title?
mpp
Testé et cela fonctionne bien, mais vous devrez probablement utiliser le plugin "migration_lookup" car le plugin "migration" est obsolète et ne fonctionnait pas déjà sur mes dernières versions. Les éléments suivants ont fonctionné pour moi pour importer des images utilisateur: plug-in: migration_lookup migration: my_file_migration source: picture De plus, si vous migrez des entités sans bundles (comme des images utilisateur), vous aurez probablement besoin du patch à partir d'ici: drupal.org/project/migrate_plus/issues / 2787219 , sinon vous obtenez une erreur "Le plugin entity_lookup nécessite une valeur_key, aucune localisée." sur la migration.
Mirsoft
Est-ce que quelqu'un pourrait expliquer comment $ entityId se trouve dans ceci?
dibs
2

J'ai beaucoup apprécié la réponse acceptée, mais elle contient déjà des définitions obsolètes et ne prend pas en charge la publication des propriétés des images alt et title. Ainsi, je l'ai un peu amélioré pour prendre en charge cela et travailler en douceur avec la dernière Drupal 8.6.x. Voici le code de MediaGenerate.php (la syntaxe Yaml appropriée est à l'intérieur du commentaire doc):

<?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
la source
2

Comme Media est un type d'entité, vous devez créer sa propre migration. Vous pouvez générer une nouvelle source à partir de la table de fichiers. Voici un exemple

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

Ensuite, migration_lookupvous pouvez mapper les champs comme celui-ci.

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

Si vous souhaitez migrer des fichiers dans Drupal 8 vers des entités multimédias, vous pouvez utiliser ce module: https://www.drupal.org/project/migrate_file_to_media

Il a un script drush, qui crée automatiquement les champs de référence du média. De plus, il détecte les images en double à l'aide d'un hachage binaire. Et il prend en charge les traductions.

Brainski
la source
1
Ce module ne résout que la migration entre les versions D8 par défaut. La question ressemble plus à la migration de D7 à D8, de sorte que le module ne peut pas être facilement utilisé (un plugin source supplémentaire pour MediaEntityGenerator.php qui lirait les données des fichiers joints dans D7 devrait probablement être créé). Il y a aussi une différence fondamentale: le module migrate_file_to_media ne convertit que les fichiers attachés à certaines entités (= type_entité et bundle sont requis à l'étape 1), tandis que la solution acceptée n'a pas cette exigence et migre d'abord toutes les entités de fichiers à partir du (D7) la source.
Mirsoft