Drupal Migrate multiples ficheros

drupal.jpg
Solucionex
18
Mar 15

En ocasiones, cuando creamos un nuevo portal con Drupal esté puede provenir de una antigua web. En estos casos suele ser necesario realizar una migración de contenidos al nuevo portal creado. Drupal posee una potente herramienta o módulo para este cometido, el modulo Migrate. Este módulo tiene una extensa documentación, donde se detallan todas las posibilidades del mismo.

En esta entrada de blog nos centraremos en la migración de los campos de ficheros múltiples, por ser considerados algo más complejos de manejar. Asumiremos un conocimiento previo de los procesos de migración con este módulo, y sólo describiremos el proceso para el caso de los ficheros.

En posteriores artículos definiremos más elementos de la migración.

Antes de entrar en materia debemos aclarar que este código es funcional en la versión 2.5 del módulo, no funcionando correctamente en la nueva versión del módulo 2.7.

Tomaremos como referencia la siguiente clase de migración:

description = t('Catálogos'); $query = Database::getConnection('default', 'for_migration') ->select('catalogos', 'c') ->fields('a', array('id', 'titulo', 'descripcion', 'activo')) ; $this->source = new MigrateSourceSQL($query); $this->destination = new MigrateDestinationNode('catalogos', array('text_format' => 'full_html')); $this->map = new MigrateSQLMap($this->machineName, array( 'id' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'alias' => 'a', ) ), MigrateDestinationNode::getKeySchema() ); $this->addFieldMapping('title', 'titulo'); $this->addFieldMapping('field_cuerpo', 'descripcion'); $this->addFieldMapping('field_area', 'nombre'); $this->addFieldMapping('status', 'activo'); $this->addFieldMapping('language')->defaultValue('es'); // Field Files from catágolos $this->addFieldMapping('field_archivos', 'file_list'); $this->addFieldMapping('field_archivos:description', 'file_descriptions'); $this->addFieldMapping('field_archivos:file_class')->defaultValue('MigrateFileUri'); $this->addFieldMapping('field_archivos:language')->defaultValue('es'); $this->addFieldMapping('field_archivos:destination_dir')->defaultValue('public://archivos/catalogos'); $this->addFieldMapping('field_archivos:file_replace')->defaultValue('FILE_EXISTS_REPLACE'); $this->addFieldMapping('field_archivos:preserve_files')->defaultValue(FALSE); $this->addFieldMapping('field_archivos:')->defaultValue($relativepath .'/catalogos'); } public function prepareRow($current_row) { $query = Database::getConnection('default', 'for_migration') ->select('archivos', 'f') ->fields('f', array('fichero', 'etiqueta')); $db_and = db_and(); $db_and->condition('f.idCatalogo', $current_row->id, '='); $query->condition($db_and); $results = $query->execute(); $current_row->file_list = array(); $current_row->file_descriptions = array(); foreach ($results as $row) { $current_row->file_list[] = $row->fichero; $current_row->file_descriptions[] = $row->etiqueta; } return TRUE; }

Con está clase pretendemos migrar un conjunto de catálogos que teníamos almacenados en una base de datos MySQL, cada uno de estos catálogos tiene un conjunto de ficheros, que obtenemos con el cruce de la tabla archivos.

Nos centraremos en el siguiente fragmento de código: // Field Files from catágolos $this->addFieldMapping('field_archivos', 'file_list'); $this->addFieldMapping('field_archivos:description', 'file_descriptions'); $this->addFieldMapping('field_archivos:file_class')->defaultValue('MigrateFileUri'); $this->addFieldMapping('field_archivos:language')->defaultValue('es'); $this->addFieldMapping('field_archivos:destination_dir')->defaultValue('public://archivos/catalogos'); $this->addFieldMapping('field_archivos:file_replace')->defaultValue('FILE_EXISTS_REPLACE'); $this->addFieldMapping('field_archivos:preserve_files')->defaultValue(FALSE); $this->addFieldMapping('field_archivos:')->defaultValue($relativepath .'/catalogos'); } public function prepareRow($current_row) { $query = Database::getConnection('default', 'for_migration') ->select('archivos', 'f') ->fields('f', array('fichero', 'etiqueta')); $db_and = db_and(); $db_and->condition('f.idCatalogo', $current_row->id, '='); $query->condition($db_and); $results = $query->execute(); $current_row->file_list = array(); $current_row->file_descriptions = array(); foreach ($results as $row) { $current_row->file_list[] = $row->fichero; $current_row->file_descriptions[] = $row->etiqueta; } return TRUE; }

La función prepareRow es una función que nos permitirá realizar un tratamiento de la tupla de la base de datos origen (web antigua) que tratamos de mapear en el tipo de contenido de nuestra nueva web en Drupal.

En esta función obtendremos el conjunto de ficheros y etiquetas para cada catálogo que estamos procesando, y los iremos almacenando en dos arrays: $current_row->file_list y $current_row->file_descriptions. De este modo para cada catálogo que estemos procesando, habremos creado un array con los ficheros del mismo y otro con las descripciones de estos.

Estos arrays son asignados a dos variables o campos de $current_row, que almacena los datos de la fila que se está procesando en ese momento, fruto de la query:

$query = Database::getConnection('default', 'for_migration') ->select('catalogos', 'c') ->fields('a', array('id', 'titulo', 'descripcion', 'activo')) ;

Una vez que tenemos estos campos construidos necesitamos mapearlos al campo de múltiples ficheros de nuestro tipo de contenido:

// Field Files from catágolos $this->addFieldMapping('field_archivos', 'file_list'); $this->addFieldMapping('field_archivos:description', 'file_descriptions'); $this->addFieldMapping('field_archivos:file_class')->defaultValue('MigrateFileUri'); $this->addFieldMapping('field_archivos:language')->defaultValue('es'); $this->addFieldMapping('field_archivos:destination_dir')->defaultValue('public://archivos/catalogos'); $this->addFieldMapping('field_archivos:file_replace')->defaultValue('FILE_EXISTS_REPLACE'); $this->addFieldMapping('field_archivos:preserve_files')->defaultValue(FALSE); $this->addFieldMapping('field_archivos:')->defaultValue($relativepath .'/catalogos');

En primer lugar mapeamos los ficheros con el campo correspondiente del tipo de contenido "field_archivos". Tras ello establecemos otros atributos de este campo, como el lenguaje, las descripciones, la ruta destino de los ficheros...

Describiremos algunos de ellos a continuación:

  • file_class. Clases de migración para ficheros, existen 3: MigrateFileuri, MigrateFileBlob y MigrateFileFid. En nuestro caso usamos la primera de ellas, ya que necesitamos copiar los ficheros a los que hacen referencia. Si trabajásemos con ficheros en base de datos, o los ficheros ya existiesen en Drupal, utilizaríamos las otras dos clases.
  • destination_dir. Ruta destino donde Drupal almacenará los ficheros, si no se indica, Drupal utilizará por defecto la que hayamos definido en dicho campo en el tipo de contenido.
  • file_replace. Esta opción define el comportamiento cuando importamos un fichero que ya existía. En nuestro caso reemplazamos el fichero, existen otras políticas que permiten su reutilización o renombrado.
  • preserve_files. Esta opción nos permite decidir que ocurrirá con los ficheros cuando hagamos un rollback a la migración, en nuestro caso no mantendremos los ficheros al dar marcha atrás en la migración. De este modo al hacer rollback eliminaremos los ficheros que habíamos copiado.
  • source_dir. Directorio origen donde se buscarán los ficheros.