Image
Migration de données Drupal

Migrer les données de crop du module Drupal 7 "Manual Crop" vers le module "Focal point" dans Drupal 8/9/10

Comment récupérer les données de crop de "Manual Crop" dans Drupal 7 ?

Dans Drupal 7, le module "manual crop" enregistre ses données dans la table "manualcrop" de la base de données. Pour chaque crop, il y a une entrée dans cette table avec :

  • l'identifiant "fid" de l'image,
  • le nom de style "style_name",
  • la position de l'ancre de crop (x, y),
  • les dimensions du crop (width, height).

Donc si on veut récupérer les données de crop pour une image, on peut utiliser la requête MySql suivante (par exemple pour un fid=1) :

SELECT     x, y, style_name, width, height

FROM       manualcrop

WHERE      fid = 1

 

Cette requête retourne toutes les entrées de crop manuels existant pour ce fichier. Ce sont ces données que l'on utilisera pour importer les cropts dans Drupal 8/9/10.

Comment sont enregistrées les données de crop de "Focal point" dans Drupal 8/9/10 ?

Le module "Focal point" se base sur la Crop API pour enregistrer les données de crops. La Crop API définit un type d'entité crop avec des champs.
Ce type d'entité crop enregistre des données dans la table "crop_field_data".

Les propriétés de crop sont : x, y, width et height. 
Nous avons également les propriétés liées à l'entité :

  • cid,
  • vid,
  • type,
  • langcode,
  • entity_id,
  • entity_type,
  • uri.

Le "cid" est l'ID d'entité crop, "vid" est l'ID de revision, "type" est le type de crop (pour Focal point c'est crop). Le champ "entity_id" est l'ID de l'objet recadré et la plupart du temps ce sera le fid de l'image ayant comme "entity_type" la valeur "file". L'URI est l'uri du fichier tel que trouvé dans la table des fichiers "file_managed" pour le fichier correspondant.

La façon dont le module "focal point" fonctionne est qu'il utilise les coordonnées x,y comme des coordonnées absolues pour représentés le point de focus sur l'image d'origine. Ensuite, pour les styles d'image (image style) utilisant l'effet focal point, l'API du module "Focal Point" va convertir les coordonnés absolues en coordonnées relatives afin de générer les crop styles d'image.

Sachant ce fonctionnement, afin de migrer les données de crop pour "Focal point", une bonne approche est d'écrire un plugin de migration pour des entités de type crop.

Un peu de géométrie pour mieux comprendre le crop et convertir les données de "Manual crop" vers "Focal point"

Un crop est un zone rectangulaire à l'intérieur d'une image. Le sommet en haut à gauche du recadrage est appelé une ancre.

Le module "Manual crop" enregistre les coordonnés de l'ancre ainsi que la largeur et la longueur de la zone de recadrage. Les coordonnées sont relatives au sommet en haut à gauche de l'image : x est la position horizontale (de gauche à droite) et y la position verticale (du haut vers le bas).

Le module Focal Point enregistre uniquement les coordonnées du centre du recadrage relativement au sommet en haut à gauche de l'image. C'est parce que cette information est suffisante pour déduire le reste et centrer les recadrages.

Par conséquent, afin d'importer les données provenant du module "Manual Crop" vers des données pour "Focal Point", il faut calculer la position du centre de la zone de recadrage à l'intérieur des zones de recadrage de Manual Crop. 

La formule mathématique pour y arriver est donc : 

x(from focal point) = x(from manual crop) + width(from manual crop)/2 

y(from focal point) = y(from manual crop) + width(from manual crop)/2 

Migration vers des entités Crop

Notre contexte

Dans notre contexte, nous avons déjà migrés les fichiers publiques en utilisant un plugin de migration d'entité de fichier. Dans certains cas, les entités de crops sont créées automatiquement lors de la création des entités de fichiers avec par défaut une position de crop qui correspond au centre de l'image. 

Donc ce dont on a besoin dans ce cas, c'est de définir un plugin de migration qui sera capable de créer ou de mettre à jour des entités de crops déjà existantes. Pour le cas de mettre à jour des entités existantes, nous allons utilisé l'option "overwrite_properties" dans la configuration de destination du plugin et nous ferons correspondre le cid existant dans la configuration du process du plugin. Ainsi si un crop existe, cela mettra à jour les valeurs calculées à la place des valeurs par défaut.

Plug-in source

Nous avons besoin d'écrire un plugin source custom qui va aller récupérer les données dans de manual crop dans la base de données Drupal 7 mais aussi récupérer les crops existant dans Drupal 9/10 si elles sont déjà crées..

Voici une fonction query qui récupère les fichiers images dans Drupal 7:

public function query() {
    $query = $this->select('file_managed', 'f')
      ->fields('f')
      ->condition('f.uri', 'temporary://%', 'NOT LIKE')
      ->condition('f.type', 'image', '=')
      ->orderBy('f.timestamp');

    // Filter by scheme(s), if configured.
    if (isset($this->configuration['scheme'])) {
      $schemes = [];
      // Remove 'temporary' scheme.
      $valid_schemes = array_diff((array) $this->configuration['scheme'], ['temporary']);
      // Accept either a single scheme, or a list.
      foreach ((array) $valid_schemes as $scheme) {
        $schemes[] = rtrim($scheme) . '://';
      }
      $schemes = array_map([$this->getDatabase(), 'escapeLike'], $schemes);

      // Add conditions, uri LIKE 'public://%' OR uri LIKE 'private://%'.
      $conditions = $this->getDatabase()->condition('OR');
      foreach ($schemes as $scheme) {
        $conditions->condition('f.uri', $scheme . '%', 'LIKE');
      }
      $query->condition($conditions);
    }

    return $query;
  }

 

Voici la fonction prepareRow qui va dans un premier temps vérifier les données de crops déjà existantes dans Drupal 9/10 suite à la migration de fichiers (le cid dans la table "'crop_field_data'") pour gérer la mise à jour d'entités de crop déjà existantes. Dans cette fonction, on va aussi récupérer les données dans la table "manualcrop" de la base Drupal 7 et faire le calcul des coordonnées pour Focal point et assigner ces valeurs pour qu'elles soient prises en compte dans la migration : 

public function prepareRow(Row $row) {
    $crop_type = \Drupal::config('focal_point.settings')->get('crop_type');
    $row->setSourceProperty('type', $crop_type);

    // Get mapped fid.
    $new_fid = $this->setUpDatabase(['key' => 'default'])->select('migrate_map_file', 'm')
      ->fields('m', ['destid1'])
      ->condition('m.sourceid1', $row->getSourceProperty('fid'), '=')
      ->execute()
      ->fetchField();
    if ($new_fid) {
      $file_storage = \Drupal::entityTypeManager()->getStorage('file');
      $file = $file_storage->load($new_fid);
      $row->setSourceProperty('entity_id', $new_fid);
      $row->setSourceProperty('entity_type', 'file');
      $row->setSourceProperty('uri', $file->getFileUri());

      // Get crop cid if it already exists.
      $cid = $this->setUpDatabase(['key' => 'default'])->select('crop_field_data', 'c')
        ->fields('c', ['cid'])
        ->condition('c.entity_id', $new_fid, '=')
        ->execute()
        ->fetchField();
      if ($cid) {
        $row->setSourceProperty('cid', $cid);
      }

      // Get D7 manual crop data.
      $style_names = [
        'manual_crop_320x213',
        'manual_crop_326x171',
        'manual_crop_735x412',
        'manual_crop_640x198',
        'manual_crop_640x274',
        'manual_crop_408x265',
      ];
      $manual_crop_data = $this->select('manualcrop', 'mc')
        ->fields('mc')
        ->condition('fid', $row->getSourceProperty('fid'), '=')
        ->condition('style_name', $style_names, 'IN')
        ->where('x <> 0 OR y <> 0')
        ->execute()
        ->fetchAll();

      if (isset($manual_crop_data[0])) {
        $first_crop = $manual_crop_data[0];
        $x = $first_crop['x'] + round($first_crop['width'] / 2);
        $y = $first_crop['y'] + round($first_crop['height'] / 2);
        $row->setSourceProperty('x', $x);
        $row->setSourceProperty('y', $y);
      }
    }

 

Le plugin de migration

Le plugin de migration complet :

id: edito_crop
label: Images Crops
audit: true
migration_group: EDITO
migration_tags:
  - EDITO
source:
  plugin: edito_d7_crop
  scheme: public
  key: migrate
process:
  cid: cid
  type: type
  entity_id: entity_id
  entity_type: entity_type
  uri: uri
  x:
    - plugin: get
      source: x
    - plugin: skip_on_empty
      method: row
  y:
    - plugin: get
      source: y
    - plugin: skip_on_empty
      method: row

destination:
  plugin: 'entity:crop'
  overwrite_properties:
    - x
    - y

 

Articles pouvant vous interesser

Image
Images responsives, écrans rétina ready et format Webp
Responsive Image
Webp
Retina
Performances
Image
A quoi s'attendre avec Drupal 10
Drupal 10