Hero

Cómo cambiar el tipo de entity field desde MySQL en Drupal 7

Septiembre 24, 2014

Isaac Gasi
Drupal
Field API
MySQL

Hablemos de esos proyectos donde el reto no es únicamente desarrollarlo sino lograr interpretar lo que el Cliente quiere pero no sabe como lo quiere, estos proyectos se vuelven complejos porque siempre los requerimientos cambian, y cuando ya tienes definida una arquitectura y de repente tienes que cambiarla dos días antes de ponerlo en productivo, te pone un poco a temblar.

  1. El problema

Al inicio del proyecto se definieron fields de tipo decimal porque se pretendía generar gráficas con estos valores, sin embargo, el cliente envía contenido que no siempre son decimales.

Al final de cuentas se toma la decisión de que es mejor manejar texto para todas esas variaciones, no sería nada difícil solucionarlo si no tuviéramos miles de nodos ocupando este field :S puesto que de esta manera sólo tendríamos que eliminar el field y crear uno nuevo, pero tenía que existir algo divertido sino no estaría escribiendo esta entrada.

  1. La solución

Llegado a este punto vienen las interrogantes ¿Si puedo cambiar la definición del field? ó ¿Puedo hacer que el decimal se convierta en string?

Esto se puede hacer de una manera rápida si nos metemos directamente a la base de datos, ahí encontraremos una tabla por field para el caso de Drupal 7, por ejemplo si tenemos un field llamado field_myfieldname vamos a encontrar un tabla llamada field_data_field_myfieldname.

Si tenemos activas las revisiones, entonces también habrá una tabla para este field que se llame field_revision_field_myfieldname, ademas de eso vamos a encontrar la definición de este field en otra tabla que se llama field_config.

Lo que sigue ahora es modificar estas tablas para poder hacer el cambio de decimal a string.

2.1 Estructura de la base de datos.

Analicemos primero la estructura de las tablas dentro de mysql, en este caso vamos a tratar field_value, pero sólo hablaré de las columnas que son relevantes para este caso en particular, veamos la estructura de la tablas con los siguientes comando de SQL.

<pre title="Estructura de un field decimal">describe field_data_field_value;

1 table describe field data decimal type

<pre title="Estructura de la revision en un field decimal">describe field_revision_field_value;

2 table describe field revision decimal type

Hasta el momento las dos tablas asociadas al field contienen la misma estructura, de aquí la columna que nos interesa es field_value_value la cual es de tipo decimal(10,1), este tipo de campos son tipo para los fields de tipo decimal, ahora veamos como se referencia una estructura de una tabla de tipo text.

<pre title="Estructura en un field de tipo text">describe field_revision_field_divident_label;

3 table describe field data text type

Como se puede apreciar hay una columna adicional field_divident_label_format y que ahora el tipo de columna field_divident_label_value es varchar con longitud de 100.

Esto quiere decir que además de cambiar el tipo de columna, también tendremos que agregar posteriormente otra columna.

Para finalizar nuestro análisis veamos como es la estructura de la tabla field_config.

<pre title="Estructura de la tabla de declaración de entity fields">describe field_config;

4 table describe field config

En esta tabla encontramos una estructura diferente, las columnas que nos interesan aquí son field_name, type y data. En data vamos a encontrar toda la configuración que encontramos en los settings del field, por ejemplo si es requerido o el valor por default.

2.2. Alterar la base de datos

Ahora veamos como cambiar el tipo de la columna field_value_value de decimal(10,1) a varchar(30), el siguiente comando lo ejecutamos tanto en la tabla de field_data_field_value como field_revision_field_value.

<pre title="Cambio del value de decimal a varchar">ALTER TABLE field_revision_field_value MODIFY field_value_value varchar(30);
ALTER TABLE field_data_field_value MODIFY field_value_value varchar(30);

Adicionalmente agregamos una columna y la llamaremos field_value_format, nuevamente en las dos tablas mencionadas en el paso anterior:

<pre title="Agregar columna de fotmat para tipo text">ALTER TABLE field_revision_field_value ADD field_value_format varchar(255);
ALTER TABLE field_data_field_value ADD field_value_format varchar(255);

También debemos configurar el tipo del entity field en la tabla field_config de decimal a text:

<pre title="Redeclarar el entity field en la configuración">UPDATE field_config SET type = 'text' WHERE field_name = 'field_value';

Una vez que hagamos esto podemos ir a ver como ya cambio el tipo de field de decimal a text, es recomendable borrar cache con drush cc all. Sin embargo, aunque el cambio ha sido exitoso, nos pueden aparecer algunos mensajes de error si ingresas a la página http://example.com/admin/structure/types/manage/your-content-type/fields

5 manage fields change decimal to text with errors 0

También en http://example.com/admin/structure/types/manage/your-content-type/fields/field-name

6 edit field value with errors 0

Este problema se debe a que las opciones para cata tipo de entity field son distintas tanto para decimal, texto o cualquier otro, debemos configurar bien estas opciones. Para solventarlo hay que actualizar en la tabla field_config la columna data, para ellos vamos a correr la siguiente línea en mysql.

<pre title="Reconfigurar las opciones del entity field">UPDATE field_config 
SET data = 'a:7:{s:12:"translatable";s:1:"0";s:12:"entity_types";a:0:{}s:8:"settings";a:1:{s:10:"max_length";s:2:"30";}s:7:"storage";a:5:{s:4:"type";s:17:"field_sql_storage";s:8:"settings";a:0:{}s:6:"module";s:17:"field_sql_storage";s:6:"active";s:1:"1";s:7:"details";a:1:{s:3:"sql";a:2:{s:18:"FIELD_LOAD_CURRENT";a:1:{s:22:"field_data_field_value";a:2:{s:5:"value";s:17:"field_value_value";s:6:"format";s:18:"field_value_format";}}s:19:"FIELD_LOAD_REVISION";a:1:{s:26:"field_revision_field_value";a:2:{s:5:"value";s:17:"field_value_value";s:6:"format";s:18:"field_value_format";}}}}}s:12:"foreign keys";a:1:{s:6:"format";a:2:{s:5:"table";s:13:"filter_format";s:7:"columns";a:1:{s:6:"format";s:6:"format";}}}s:7:"indexes";a:1:{s:6:"format";a:1:{i:0;s:6:"format";}}s:2:"id";s:2:"22";}' 
WHERE field_name = 'field_value';

Ok, estoy de acuerdo se ve un tanto ruda, pero no hay mucho problema, para empezar hay que observar que dentro de la cadena que sera asignada a data hay varias ocurrencias, lo que hay que hacer antes de correrla para sus fields es:

  • Sustituir en la cadenas field_value por su field_myfieldname.
  • En todas las sustituciones antes de esa cadena existe un secuencia de caracteres similar a s:18, por ejemplo en la primera aparición del field es s:22:“field_data_field_value”; el número representa la longitud de caracteres de field_data_field_value que es 22 en este caso, deben actualizar este valor en todas las sustituciones por la cantidad de caracteres correspondientes en cada aparición.

¿Por qué hacer esto último? porque les puede aparecer en una pantalla en blanco del browser el siguiente mensaje:

Fatal error: Unsupported operand types in /path/to/Drupal/modules/field/field.info.class.inc on line 479

Y voila!!! ya no aparecen errores, les recomiendo entrar a la configuración del widget de nuestro field (field_value) y guardar la configuración que tiene sólo para actualizar correctamente los valores que hay en la tabla field_config_instance.

Hay que considerar también implementar db_change_field en lugar de un enfoque directo en bases de datos.

Espero les haya servido, Gracias.

Recibe consejos y oportunidades de trabajo 100% remotas y en dólares de weKnow Inc.