Migrate es un framework para migrar contenido desde cualquier fuente hacia drupal. Si nuestro contenido usa algún campo sin soporte para Migrate lo primero es mirar en Migrate Extras a ver si incluye soporte para ese campo o hay un parche en desarrollo. Si bien la idea es que migrate extras quede obsoleto y que cada módulo implemente su integración con Migrate, todavía incluye soporte para varios campos, y en la página del módulo hay una tabla que indica el estado de la integración para diferentes módulos. Finalmente, si no está soportado o se trata de un campo propio podemos implementar la integración nosotros mismos, y definir un field handler para migrate es muy fácil, como hicimos para serial field.

Lo primero es registrar la clase para que migrate la reconozca. En my_module.migrate.inc implementamos hook_field_migrate_api.

/**
 * Implements hook_migrate_api().
 */
function custom_field_migrate_api() {
  $api = array(
    'api' => 2,
    'field handlers' => array(
      'MigrateCustomFieldFieldHandler',
    ),
  );
 
  return $api;
}

Luego definimos una clase que herede de MigrateFieldHandler y registramos en el constructor los tipos de campos que el handler manejará.

class MigrateCustomFieldFieldHandler extends MigrateFieldHandler {
  public function __construct() {
    $this->registerTypes(array('custom_field'));
  }
}

Si queremos definir opciones para el handler o el campo tiene varios subcampos usamos el método fields para definirlos. Cada una de las entradas del array que devuelve el método estarán disponibles como destinos en las migraciones. Este ejemplo está tomado de la implementación que hicimos para Double Field, que tiene dos subcampos (first y second).

public function fields($type, $parent_field, $migration = NULL) {
    $fields['first'] = t('Subfield: Value of the first part of the Double Field.');
    $fields['second'] = t('Subfield: Value of the second part of the Double Field.');
 
    return $fields;
}

Finalmente en prepare recibimos los valores que la migración mapeó a nuestro campo y construimos el array con el valor del campo. En $values recibimos los valores primarios mapeados (los mapeados directamente a nuestro campo) y los argumentos (los valores mapeados a los subcampos u opciones definidos en fields). Por ejemplo, si en la migración tenemos estos mapeos

$this->addFieldMapping('mi_campo')->defaultValue(TRUE);
$this->addFieldMapping('mi_campo:first', 'primer_valor');
$this->addFieldMapping('mi_campo:second', 'segundo_valor');

En values tendremos

array(
  0 => TRUE,
  'arguments' => array(
    'first' => 1, // Contenido de 'primer_valor' en la fila importada.
    'second' => 2, // Contenido de 'segundo_valor' en la fila importada.
  ),
);

Esta implementación es del mismo ejemplo para double field

public function prepare($entity, array $field_info, array $instance, array $values) {
  // Extraemos los argumentos (opciones / subcampos) recibidos.
  $arguments = array();
  if (isset($values['arguments'])) {
    $arguments = array_filter($values['arguments']);
    unset($values['arguments']);
  }
  $language = $this->getFieldLanguage($entity, $field_info, $arguments);
 
  // Armamos el array de Field API para guardar.
  $return = array($language => array());
  $delta = 0;
  foreach ($values as $value) {
    foreach (array('first', 'second') as $field) {
      if (isset($arguments[$field])) {
        if (is_array($arguments[$field])) {
          $return[$language][$delta][$field] = $arguments[$field][$delta];
        }
        else {
          $return[$language][$delta][$field] = $arguments[$field] ;
        }
      }
    }
 
    $delta++;
  }
 
  return isset($return) ? $return : NULL;
} 

Nota: A partir de la versión 2.6 del módulo esto casi no es necesario, salvo para algún tipo de campo que requiera alguna lógica especial en la importación.

Para aprender más sobre migrate y cómo armar una migración la documentación del módulo es el mejor lugar para empezar.

Publicado el 19/09/2013 por ariel