Hacer migraciones/importaciones de contenido en Drupal

Portada del podcast Drupalízate
Drupalízate es un podcast semanal creado por mí, donde hablo sobre desarrollo web basado en Drupal.
El contenido central es resolver las típicas dudas que pueda tener alguien que tiene o quiere tener una web en Drupal.
Aparte de resolver dudas de "clientes", también se habla de tips, recomendaciones y buenas prácticas para el Developer que recién empiezan en este mundo.
Audio y notas del episodio

En este episodio te cuento por encima las dos formas más usadas para migrar contenido desde otras fuentes (csv,xml,json, bases de datos, wordpress, ...) a tu nuevo proyecto Drupal.

Transcripción automática de este episodio de audio (puede contener errores)

 Hola, buenas. Una semana más aquí en Drupalizate, el podcast de Drupal, donde yo, Robert Menetray, te cuento los tuquillos, los tips, las formas en las que se trabaja correctamente con proyectos Drupal. Esta semana quiero comentarte, para que sepas, cómo se tienen que hacer las migraciones de contenido. ¿Vale? Migraciones o importaciones. Depende de dónde recibes, lo vas a llamar de una forma o de otra. Primero y todo, para la gente que no sepa qué es esto, cuando hace importar contenido de una web antigua, o de una cosa que no es una web, a un proyecto de Drupal, a una web hecha en Drupal, te hace falta una forma de leer estos datos, procesarlos, convertirlos a valores útiles y guardarlos en Drupal. ¿Vale? Por ponerte un ejemplo, puedes tener un Excel o un CCV, donde tienes unas fechas en un formato, yo que sé, en horario de Madrid, en zona horaria, y lo quieres convertir a formato UNIX, y esto guardarlo en un campo dentro de Drupal. Por ponerte un ejemplo. O tienes un, yo que sé, un XML que se genera en un ERP, o un JSON que se genera en tu ERP, lo exportas allí, lo quieres subir a Drupal para que te creen las cuentas de usuarios, con los nombres e emails de los usuarios de la web. ¿Puede decir algo? ¿Vale? Digamos que en Drupal hay como dos formas, simplificándolo mucho, de hacer importaciones de contenido. Y como digo de contenido, me refiero a usuarios, a páginas, a cualquier cosa que sea una entidad en Drupal. Por ejemplo, migrar imágenes. Solo quieres migrar ficheros. PDFs, imágenes, audios, vídeos, lo que quede conveniente. Ficheros en general. Lo que digo, hay dos formas. Digamos, la primera, con la que piensa la gente que no es de Drupal es, vale, pues, tocar código, modificó código PHP, hago un módulo custom con PHP, y bueno, pues, me comunico con base de datos, para que se guarden los datos que yo quiero importar. Y llegados a este punto, es un sí, pero no. Sí, puedes hacer una migración por código, pero usando las funciones que tienes en Drupal, para trabajar con las entidades. En Drupal no haces consultas directamente a base de datos para meter un insert. Eso está mal. La forma correcta es usar las funciones que tienes en Drupal, para guardar, por ejemplo, crear archivos, o dar de alta a usuarios, o dar de alta nodos. ¿Por qué? Por ejemplo, cuando das de alta un nodo, si tienes el módulo path auto, automáticamente te va a crear la URL para esa página. Con lo cual es una práctica crear la entidad del nodo usando la entidad del nodo, no directamente toqueteando la base de datos con código totalmente custom, porque la vas a liar. Y lo mismo con los usuarios, cuando le haces alto a usuarios, te puede interesar que se envíe un correo notificando que al usuario se le ha dado de alta, y que le llegue un, ¡hey! te hemos dado de alta la web. Aquí tienes el link para entrar. Si usas las funciones de Drupal, que trabajas con entidades, en este caso usuarios, tienes las funciones para, por ejemplo, enviar los mails de esta forma. O, por ejemplo, generar la contraseña, o sea, a partir del String, que te genera la contraseña en la web de envase de datos como tal. Es una forma de ahorrarte el paso de generar tú la encriptación de la contraseña y tenerla que meter en base de datos. Lo que digo, en Drupal no se trabaja directamente en base de datos. Se trabaja con las entidades y con las funciones API que tienes de Drupal. Esto si lo quieres hacer todo por código. Pero, de forma de ver, en pocas ocasiones te hace falta hacer una migración toda por código custom. Es mejor usar el módulo Migrate. El módulo Migrate te viene en el code de Drupal. Tú instalas un Drupal por defecto en Drupal 8 y 9 y ya te viene este módulo dentro. Solo has de activarlo porque por defecto viene desactivado. Porque normalmente en webs nuevas no siempre hace falta hacer una migración. En webs que vengan de una web vieja, sí, hay webs nuevas que directamente es una web nueva, que el contenido es nuevo. No siempre hace falta migraciones como tal. Total, es activar el módulo este módulo. Tampoco voy a hacer un tutorial de este módulo aquí, pero para que me entendáis un poco, este módulo trabaja con fichieros yaml, de configuraciones, donde básicamente cada migración que quieras crear sea un fichier de yaml y ahí configuras el origen de datos, que puede ser una base de datos, un xml, un json, un csv, depende de cada caso. Dependiendo del origen de datos, tendrás que poner algún parámetro más. Por ejemplo, si el origen de datos es una url, pues un parámetro es cuál es la url, de dónde se coge los datos. Si es una url y los datos devueltos son un json, se ha de configurar que es un json, para que el mismo dupal te de los datos ya procesados del json. Lo primero que hay que hacer configurar en el yaml es el origen de datos, cuál es. Después, configurar el mapeado. En el caso de que sea un json, si por ejemplo el json devolviese el nombre de usuario y correos, el mapeado sería el nombre de usuario corresponde con la variable name, el mail correspondería con la variable mail. Y así. Y si fuera un csv, dirías que la primera columna del csv corresponde con el nombre de usuario y la segunda columna del csv corresponde con el correo electrónico del usuario. Al final, mapear los datos que vienen de origen con que se corresponden, con un nombre que tú le pongas que sea lógico. Para saber a qué hace referencia esta variable. Y después, en el mismo yaml, configuras el destino de estos datos. Con lo cual tienes las variables que has puesto en el mapeado y aquí le dices el destino, ah, pues el correo electrónico que me viene en la segunda columna del csv es el campo mail del usuario o es el campo x de este nodo. Vale, marcas el destino, marcas a qué entidad corresponde, si es un nodo, o es un usuario, o un medio, o lo que sea, y dentro de esta entidad a qué campo corresponde. Que puede ser un campo, una propiedad de la misma entidad, que por ejemplo el título, o el nombre, o el mail del usuario, o sea, título del nodo, o nombre, o mail del usuario, son campos fijos que en Drupal han de estar sí o sí. Son campos de propiedad. Si son campos configurados, pues son campos normales, que es, digamos, lo de cómo explico. Los que son de propiedad normalmente no tienen el field barra baja delante. Los que son agregados por configuración, sí. Vale, se pueden diferenciar así. Los que son propios de la entidad no tienen el field barra baja delante. Vale, dicho todo esto, ya está. Si no hace falta modificar los datos de origen, ya tienes la migación hecha. El Migrate te da un comando para ejecutar esta migación desde línea de comandos o desde la interfaz del Migrate te salda la confiación que tú has creado y le puedes dar al botón importar. Y va a leer SSSV o SSX, o lo que tengas, va a coger el mapeado y según el mapeado y el destino lo va a guardar en Drupal. Así de simple. Aquí vienen las complicaciones. En muchos proyectos puede ser de que te haga falta modificar los datos. Porque la fecha que viene en origen tiene una zona horaria, porque el campo de, yo que sé, de texto es más largo de lo que debería y lo quieres cortar, o quieres eliminar palabras del campo de texto para que no se guarden en Drupal esas palabras. Digamos que quieres procesar los datos para hacer algo. Por ejemplo, otro típico es tengo un campo dirección donde por ejemplo sale la ciudad, pero yo en Drupal lo quiero guardar como un campo de latitud y longitud para pintarlo en un mapa. O sea, he de procesar los datos para convertir un campo tipo texto a un campo tipo latitud y longitud de geoposicionamiento. O lo mismo, por ejemplo, tengo un campo tipo texto y lo quiero convertir a un campo tipo fecha para guardar en Drupal en la fecha. O un campo tipo texto lo quiero convertir en un campo numérico porque en Drupal quiero que sea un número. Al final es, he de jugar con los datos, procesarlos, modificarlos y que esto se guarde en Drupal. Otro típico es tengo el nombre de categorías separadas por comas y quiero que en Drupal esto sea una taxonomía. Con lo cual quiero que me quede entidad de taxonomía y después en el nodo me asigne el id de la taxonomía. Al final todo esto, algunas se hacen de forma, por ejemplo, de taxonomía casi por defecto, sin apenas tocar nada. Otras tienes que jugar con los plugins que te da el mismo migrate y en la configuración YAML especificas de vale este campo no es el campo dos puntos no me da la variable de origen, es el campo dos puntos usa este plugin que concatena, que modifica la fecha que hace X de este campo de origen. Básicamente es si los plugins que te vienen por defecto te sirven, que en la mayoría de casos sí, digamos que en el 80% de casos los plugins que vienen en migrate ya te sirven por defecto, no hace falta que crees plugins nuevos. Una flexibilidad que te da el migrate es que puedes crear plugins nuevos. En este 20% que te hace falta para migraciones mucho más complejas tienes la flexibilidad, el poder de poder hacer plugins hechos a medida para este proyecto, porque te hace falta que, yo que sé, que en el media cada vez que se guarda un fichero hago una consulta a una API externa, coja valor desde allí porque el media no es solo un fichero sino que tiene campos que guarda X relacionados con el media y queremos que cada vez que se guarde el nodo genere los medias y cada vez que se genera el media guarde datos relativos a ese media, por ejemplo. Lo puedes complicar dependiendo de cómo de complejo sea tu proyecto, pero al final esto, el migrate es muy potente así que te ahorra bastante tiempo de desarrollo y una parte muy buena del migrate también son las migraciones incrementales. El migrate te gestiona lo que es las migraciones por hash o por, no sé el nombre, marca de agua y no es marca de agua, nivel de agua creo que le llamaban. Básicamente es la migra... imagínate una migración de una base de datos, tienes que migrar, yo que sé, 100 páginas, o sea 100 registros que están en la base de datos, que son 100 páginas de un WordPress. Si lo migramos hoy, de aquí a dos días, porque estamos desarrollando la web, de aquí a dos días en la web vieja modifican X contenido con lo cual alguna de esas páginas ha tenido valores modificados. La migración de aquí dos semanas antes de salir a producción has de volver a migrar otra vez el contenido, pero quizá no te hace falta migrar otra vez todas las 100 páginas, solo hace falta actualizar esas dos páginas o tres que hayan modificado. Aquí entra lo de migraciones incrementales. En Drupal tenemos lo que es con hash, que es cada vez que se migra un ítem se genera un hash con los valores de origen y cada vez que se intenta migrar un ítem nuevo se compara ese hash con el hash existente. Si el hash es el mismo es que no ha sido modificado, con lo cual no se toca. Que el hash es distinto o no existe es un ítem o modificado o nuevo, con lo cual sí se va a importar. Esto simplifica mucho y reduce mucho los tiempos de importación. En importaciones muy grandes donde hay cambios relativos, pero puede ser que el proyecto se alargue meses en el desarrollo, no quiere estar constantemente migrando 20.000 registros o 100.000 registros, que es migrar solo los que se han ido modificando o quedando de nuevos. Y esto con el hash, con el seguimiento de cambios, pero básicamente es una configuración que activas en el yaml de decir quiero que en esta migración tengas en cuenta los cambios. Y esto intentamente te genera un hash y tu te despreocupas de esto. Solo sabes que cada vez que ejecutas la migración va a inspeccionar si hacía falta o no actualizar esos datos. Y otra forma es si no quieres usar el hash, puedes usar el nivel de agua. Que básicamente es usar un campo, normalmente un campo numérico, un id, por ejemplo, o un campo fecha, y solo imposes elementos más nuevos a ese campo. Por ejemplo, si usamos un campo id y tenemos hasta el día de hoy 100 ids, de aquí a dos días que en una página nueva, esa página tendrá el id 101. Cuando la migración intente migrarlo, verá de que ah, nos quedamos en el id 100, pues estos ya ni los mido. Ah, hay un id nuevo que es el 101, ah, este no lo tengo, lo migro. Con lo cual la migración se salta a los 100 primeros y irá directamente al nuevo. Y como digo esto, para tiempo de importación reduce muchos tiempos en importaciones muy grandes. Y si enviaste un campo id a un campo de fecha, lo mismo. Te importará solo, por ejemplo, los que tengan una fecha de actualización más nueva que la que se guardó. Te puede servir como un caso de ejemplo, en vez de usar los hash, se usa un campo, digamos que, usamos como una marca de que ese contenido ha sido modificado. Pero lo típico es por la fecha de creación o fecha de actualización. Así que, sí, es muy potente usar el Migrate para esto. Y otras ventajas de Migrate que te permite hacer un rollback. Migrate te permite tirar para atrás, una vez importados, por ejemplo, los 100 ítems que decía antes, si ves que algo ha salido mal, usando un comando o desde interfaz gráfica puedes hacer un rollback, te eliminará esas páginas que ha creado el Migrate. Pero no te eliminará las páginas que se ha creado manualmente el usuario, porque ha ido por interfaz creándolas. Esto va muy bien a veces cuando haces pruebas. Aunque te recomiendo siempre hacer esto en local, no en producción. Pero que veas que hay veces que migres, por ejemplo, taxonomías y quieres que se eliminen las taxonomías creadas desde la migración, pero no las taxonomías creadas por el cliente final desde interfaz gráfica. Como digo, esto es muy potente. Los rollbacks y lo de usar el hash para detectar cambios te simplifican mucho la vida. Y migraciones también. Así que yo te recomiendo siempre que puedas usar el módulo Migrate para migraciones. Pues otros temas aparte. Por ejemplo, en Migrate también. Por temas multi idioma, has de hacer una migración para cada idioma. Primero es una migración en el idioma original, que quieres que se importe. Si el idioma original o principal de tu web es el inglés, has de migrar el contenido en inglés. Y después una migración para cada una de las traducciones, donde le marcarás el ID de la página correspondiente. La ventaja que tiene Migrate es que el ID no hace falta que tú lo sepas. Tú al Migrate le dices, este campo, el ID en el CSV o en la web antigua, el ID que se usaba en WordPress era este. Pues estamos, imagínate, importando una web de WordPress a tu par. Pues el ID que se usaba en WordPress es este. El ID que se usa en la traducción es el mismo del de WordPress. Y el migrate él solito vincula los dos ID y sabe de que el nodo que una vez ha creado en inglés usa el mismo ID internamente que el que ha de quedar en español de la misma página de WordPress y automáticamente lo añade como traducción. Vale. Migrate simplifica mucho el tema de migraciones. Si has de trabajar con migraciones, sobre todo cuando son importaciones muy grandes de contenido, mírate el Migrate. ¿Cuándo no recomiendo el Migrate? Cuando son cosas hiperpersonalizadas, cuando tiene que ser una importación periódica, porque Migrate está pensado sobre todo para migraciones de ejecutar manualmente una o determinadas veces. Normalmente es para mover una web vieja a una nueva, pero no está pensado para ser importaciones periódicas, semanales o cada X horas. Yo lo he hecho, pero no es lo mejor, sobre todo por el tema de rendimiento. En casos donde la importación es periódica o es muy hecha medida, yo te diría que es mejor que sea por código custom, pero alguien que sepa muy bien lo que está haciendo. Vale. Y nada más. Creo que no me dejo nada así. Lo importante lo he dicho. Y nada, que de todo esto hay módulos contribuidos que extienden la funcionalidad del Migrate. Te añade nuevos plugins, te añade nuevos source o te añade nuevos procesadores. Vale. Por ejemplo, Paragraph, cuando estás en modo Paragraph, te viene ya el mismo plugin para poder crear paragraf de páginas directamente de forma simple. Vale. Y nada más, que me he alargado mucho en este episodio. Espero que os sirva y nada, que en el siguiente episodio creo que me voy a meter con los junios. Estad atentos.

¿Tienes algún proyecto en mente?

Si quieres hacer algo en Drupal tal vez puedas contratarme.

Ya sea para consultoría, desarrollo o mantenimiento de sitios web Drupal.