¿Cómo cambiar la longitud de la configuración de campo?

46

He establecido una vez en un sitio web un límite de longitud a un campo. Y ahora el cliente quiere poner más personajes en ese campo.

No puedo cambiar el tamaño máximo de Drupal porque recibo el siguiente mensaje de error:

Hay datos para este campo en la base de datos. La configuración del campo ya no se puede cambiar.

Sin embargo, debe haber una solución. ¿Debo cambiarlo en la base de datos (el campo es uno implementado por el módulo Field-collections )?

Ek Kosmos
fuente
¿Puedes decirnos qué versión de Drupal y CCK? ¿También hay módulos CCK contrib?
Patrick
La versión de Drupal es 7.
Ek Kosmos
¿Y no puede modificarlo en la sección administrar campos de tipo de contenido? Debería poder modificarlo en cualquier momento. Puede darle una advertencia, pero aún así debería permitirlo. Esto puede ser un error / limitación en el módulo de colecciones de campo.
Patrick
¿Has intentado usar grupos de campo? Ahora puede hacer cosas como duplicación de grupo que no podía hacer antes.
Patrick
¡No puedo modificarlo en la sección de gestión de campos de tipo de contenido! Este es el punto. Drupal no me dejes hacerlo.
Ek Kosmos

Respuestas:

89

La solución Dylan Tack es la más fácil, pero personalmente disfruto explorando los barrios internos de la base de datos de Drupal para ver cómo se manejan las cosas allí.

Entonces, suponiendo que tiene un campo de texto cuyo nombre de máquina es field_text de 10 caracteres que desea aumentar a 25:

  • los datos se almacenarán en dos tablas: field_data_field_text y field_revision_field_text
  • la definición se almacena en field_config para los datos de almacenamiento y field_config_instance para cada instancia de este campo (cosas como etiqueta).

Ahora hagamos una pequeña cirugía de corazón.

  1. Modifique las definiciones de columnas de las tablas de datos:

    ALTER TABLE `field_data_field_text` 
    CHANGE `field_text_value` `field_text_value` VARCHAR( 25 ) 
    CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
    
    ALTER TABLE `field_revision_field_text` 
    CHANGE `field_text_value` `field_text_value` VARCHAR( 25 ) 
    CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
  2. Cambie la columna de definición , esta es muy complicada porque está almacenada en un BLOB , pero eso no es algo que lo detenga por hacerlo.

    • Diseccionar las entrañas de esta cosa BLOB :

    SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) 
    FROM `field_config` WHERE field_name = 'field_text';
    • Esto te dará algo como:

    a:7:{s:12:"translatable";s:1:"1";s:12:"entity_types";a:0:{}s:8:"settings";a:2:
        {s:10:"max_length";s:2:"10";s:17:"field_permissions";a:5:
        //a lot more stuff...
    • Esta es una matriz serializada de PHP , lo interesante es que s:10:"max_length";s:2:"10";significa que esta matriz tiene una propiedad llamada max_length(cuyo nombre es una cadena de 10 caracteres, de ahí la "s") cuyo valor es 10 (que es una cadena de 2 caracteres). Es bastante fácil, ¿no?

    • Cambiar su valor es tan fácil como reemplazar la s:2:"10"pieza por s:2:"25". Tenga cuidado: si su nuevo valor es más largo, debe adaptar la parte "s", por ejemplo, poner 100 será s:3:"100"como 100 longitud es 3.

    • Volvamos a poner este nuevo valor en la base de datos, no olvides mantener toda la cadena.

    UPDATE `field_config` 
    SET data = 'a:7:{...a:2:{s:10:"max_length";s:2:"25";...}'
    WHERE `field_name` = 'field_text'
    • Limpia tus cachés.
  3. ???

  4. ¡LUCRO!

Por cierto, PhpMyAdmin tiene alguna configuración para permitir la modificación directa de las columnas BLOB , pero ¿por qué seguir el camino fácil?

PD: Esto también puede salvarle la vida al poner un código PHP en las vistas y obtener un WSOD debido a un error en su código.

tostinni
fuente
Esa primera declaración SQL debería decir que ALTER TABLEno SELECT TABLE. Además, puede hacerlo más limpio como: ALTER TABLE field_data_field_text MODIFY field_text_value... (MODIFICAR es como CAMBIAR cuando no desea cambiar el nombre . Y no lo hace.)
artfulrobot
44
Gracias por esto. Desearía tener más de un voto a favor.
BC01
1
Esta publicación utiliza la API de esquema de Drupal para lograr el mismo enfoque: up2technology.com/blog/converting-drupal-fields
Juampy NR
2
Si no le importa enviar sus datos serializados a Internet, encontré esta herramienta, excelente para editar: pines.sourceforge.net/phpserialeditor.php
Pete
Si recibe un error sobre 'CARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL', puede usar PhpMyAdmin.
tog22
19
function mymodule_update_7100() {
  $items = array();
  _field_maxlength_fix('field_name');
  return $items;
}

function _field_maxlength_fix($field_name, $maxlength = 255) {
  _alter_field_table($field_name, $maxlength);
  $data = _get_field_data($field_name);
  $data = _fix_field_data($data, $maxlength);
  _update_field_config($data, $field_name);
}

function _alter_field_table($field_name, $maxlength) {
  db_query("ALTER TABLE field_data_".$field_name." CHANGE ".$field_name."_value ".$field_name."_value VARCHAR( ".$maxlength." ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL");
  db_query("ALTER TABLE field_revision_".$field_name." CHANGE ".$field_name."_value ".$field_name."_value VARCHAR( ".$maxlength." ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL");
}

function _get_field_data($field_name) {
  $qry = "SELECT data FROM field_config WHERE field_name = :field_name";
  $result = db_query($qry, array(':field_name' => $field_name))->fetchObject();
  return unserialize($result->data);
}

function _fix_field_data($data, $maxlength) {
  $data['settings']['max_length'] = (string)$maxlength;
  return serialize($data);
}

function _update_field_config($data, $field_name) {
  $qry = "UPDATE field_config SET data = :data WHERE field_name = :field_name";
  db_query($qry, array(':data' => $data, ':field_name' => $field_name));
}
Kevin Thompson
fuente
Al igual que esta solución, ya que no se basa en la piratería manual de bases de datos ... ¡es esencial tener una solución replicable a través de un hook_update_N!
areynolds
9

Esto parece ser una limitación del módulo de texto actual. text_field_settings_form () tiene este comentario: " @todo : Si $ has_data, agregue un controlador de validación que solo permita que aumente la longitud máxima".

Como solución temporal, puede comentar '#disabled' => $has_dataen modules / field / modules / text / text.module, alrededor de la línea 77.

No pude encontrar un problema existente para este caso específico, pero podría mencionarlo en el # 372330 .

Dylan Tack
fuente
2
Gracias por tu respuesta. He comentado la línea y ahora puedo modificar el valor del campo, sin embargo, aparece el siguiente error después de sumbit:Attempt to update field Serial No failed: field_sql_storage cannot change the schema for an existing field with data..
Ek Kosmos
En cuanto a cometer el problema de drupal, adelante y hágalo.
Ek Kosmos
1
No pude hacer que esto funcione. Después de comentar esa línea, todavía recibí un error MYSQL que ALTER TABLE falló.
jchwebdev
Si obtiene un FieldUpdateForbiddenException: cannot change the schema for an existing field with datatambién necesita comentar L282 modules/field/modules/field_sql_storage/field_sql_storage.module.
dieuwe
El comentario de @ dieuwe es incorrecto. Ese archivo no existe en versiones recientes de D8 (si alguna vez existió). Debe comentar las dos líneas en las core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.phpexcepciones de lanzamiento con el texto "El almacenamiento SQL no puede cambiar el esquema de un campo existente". Acerca de las líneas 1312 y 1403.
Dalin
6

Drupal 7

Al crear un campo de texto en Drupal 7, debe elegir una longitud máxima para sus datos. Tan pronto como cree datos para este campo, la longitud máxima se volverá inmutable en la configuración del campo Drupal.

Es comprensible que esto se deshabilite para disminuir la longitud máxima porque podría provocar una pérdida de datos, sin embargo, debería ser posible aumentar la longitud máxima para cualquier campo. Un todo en el código del módulo de texto Drupal 7 muestra que esto fue intencionado pero nunca logrado.

Las 3 cosas que deben suceder:

  1. Cambie la longitud VARCHAR de la columna de valor en la tabla field_data_ {fieldname}
  2. Cambie la longitud VARCHAR de la columna de valor en la tabla field_revision_ {fieldname}
  3. Actualice la configuración del campo para reflejar la nueva configuración de longitud máxima La siguiente función realiza los 3 pasos y toma 2 parámetros sencillos, incluido el nombre del campo y la nueva longitud máxima.
/**
 * Helper function to change the max length of a text field.
 */
function MYMODULE_change_text_field_max_length($field_name, $new_length) {
  $field_table = 'field_data_' . $field_name;
  $field_revision_table = 'field_revision_' . $field_name;
  $field_column = $field_name . '_value';

  // Alter value field length in fields table.
  db_query("UPDATE `{$field_table}` SET `{$field_column}`=SUBSTR(`{$field_column}`, 0, {$new_length})");
  db_query("ALTER TABLE `{$field_table}` CHANGE `{$field_column}` `{$field_column}` VARCHAR( {$new_length} )");
  // Alter value field length in fields revision table.
  db_query("UPDATE `{$field_revision_table}` SET `{$field_column}`=SUBSTR(`{$field_column}`, 0, {$new_length})");
  db_query("ALTER TABLE `{$field_revision_table}` CHANGE `{$field_column}` `{$field_column}` VARCHAR( {$new_length} )");

  // Update field config with new max length.
  $result = db_query("SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) FROM `field_config` WHERE field_name = '{$field_name}'");
  $config = $result->fetchField();
  $config_array = unserialize($config);
  $config_array['settings']['max_length'] = $new_length;
  $config = serialize($config_array);
  db_update('field_config')
    ->fields(array('data' => $config))
    ->condition('field_name', $field_name)
    ->execute();
}

Una vez que esta función esté disponible en su archivo de instalación personalizado, puede crear una nueva función de actualización de la base de datos que use esta nueva función para realizar los cambios necesarios.

/**
 * Change max_length of Name field
 */
function mymodule_update_7002() {
  MYMODULE_change_text_field_max_length('field_name', 50);
}

Fuente: http://nathan.rambeck.org/blog/42-modify-drupal-7-text-field-maximum-length


Drupal 8

Aquí está la versión de la misma función propuesta por @Christopher :

/**
 * Utility to change the max length of a text field.
 *
 * @param string $field_name
 *   Field name. 
 * @param int $new_length
 *   Field length in characters. 
 *
 * @throws \DrupalUpdateException
 */
function MYMODULE_change_text_field_max_length($field_name, $new_length) {
  // The transaction opens here. 
  $txn = db_transaction();

  try {
    // Update field content tables with new max length.
    foreach (['field_data_', 'field_revision_'] as $prefix) {
      db_query('
      ALTER TABLE {' . $prefix . $field_name . '} 
        MODIFY ' . $field_name . '_value VARCHAR( ' . $new_length . ' )
      ');
    }

    // Update field config record with new max length.
    $result = db_query("
        SELECT CAST(data AS CHAR(10000) CHARACTER SET utf8) 
        FROM {field_config} 
        WHERE field_name = :field_name
      ", [':field_name' => $field_name]
    );
    $config = $result->fetchField();
    if ($config) {
      $config_array = unserialize($config);
      $config_array['settings']['max_length'] = $new_length;
      $new_config = serialize($config_array);
      db_update('field_config')
        ->fields(['data' => $new_config])
        ->condition('field_name', $field_name)
        ->execute();
    }
  }
  catch (Exception $e) {
    // Something went wrong somewhere, so roll back now.
    $txn->rollback();
    // Allow update to be re-run when errors are fixed.
    throw new \DrupalUpdateException(
      "Failed to change $field_name field max length: " . $e->getMessage(),
      $e->getCode(), $e
    );
  }
}
kenorb
fuente
1
Usamos este método drupal 8 en un proyecto y encontramos problemas por los cuales, cuando ejecutaba drush updb --entity-updateslos campos que ejecutamos a través de esta función, se marcaría como una actualización. Luego intentaría actualizar el esquema de campo nuevamente en mysql. Para nosotros, esto fallaría ya que ya había datos de campo allí. Esto impedía que se ejecutaran otras tareas de actualización.
leon.nk
Para resumir, probablemente sea más seguro crear nuevos campos y migrar datos.
leon.nk
3

Pruebe esto ... esto actualizará el tipo de datos de campo de TEXT a LONG_TEXT y actualizará la max_lengthlongitud de texto de 4000 a la longitud máxima de texto ... espero que esto ayude.

function my_module_update_1001(&$sandbox) {
  // Check if our field is already created.
  if (field_info_field('sample_text_field')) {
    db_query('ALTER TABLE field_data_sample_text_field CHANGE sample_text_field_value sample_text_field_value LONGTEXT');
    db_query('ALTER TABLE field_revision_sample_text_field CHANGE sample_text_field_value sample_text_field_value LONGTEXT');
    db_query("UPDATE field_config SET type = 'text_long' WHERE field_name = 'sample_text_field' ");

    $field = array(
      'field_name' => 'sample_text_field',
      'type' => 'text_long',
      'cardinality' => 1,
      'settings' => array(
         'max_length' => 0,
      ),
    );
    field_update_field($field);    
  }
}
Harold
fuente
3

D8

  1. Comente las dos líneas en las core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchem‌​a.phpexcepciones de lanzamiento con el texto "El almacenamiento SQL no puede cambiar el esquema de un campo existente". Sobre las líneas 1312 y 1403.
  2. En su navegador, navegue hasta /admin/config/development/configuration/single/export. El tipo de configuración es "Almacenamiento de campo" y elija el campo en cuestión. Copia la configuración.
  3. Navega hacia /admin/config/development/configuration/single/import. . El tipo de configuración es "Almacenamiento de campo". Pega la configuración. Cambia la longitud.
  4. Envíe el formulario

Nota (como probablemente ya sepa), si acorta la longitud, los datos existentes se truncarán.

Dalin
fuente
Funcionó como por arte de magia. A partir de Drupal 8.5.3, las líneas son 1505-1507 en la función protegida updateDedicatedTableSchema y 1596-1598 en la función protegida updateSharedTableSchema. ¡Asegúrese de cambiar de nuevo cuando esté listo! Gracias.
HongPong
Primero probé este enfoque. Estoy tratando de modificar un campo de párrafo. Funciona, pero de todos modos es obligatorio ALTERAR las tablas correspondientes.
Yaazkal
@Yaazkal Hmmm, esa no fue mi experiencia. ¿Estás tratando de alargar o acortar el campo?
Dalin
@Dalin alargar, de 255 a 510. Usando D 8.5.5 y los párrafos 1.3
Yaazkal
1

En Drupal 7, realicé modificaciones en 2 tablas en phpmyadmin y actualicé el caché.

  1. "field_data_field_lorem": cambió "field_lorem_value" a "texto largo"
  2. "field_config": cambió "type" a "text_long"
Jill
fuente
¿Envió esto como un parche a D7? Si este es realmente el problema, entonces realmente debería enviarles un parche para resolver este problema en el código central.
Patrick
Cambié mi valor de tamaño de campo de phpmyadmin (de 10 a 25 de tipo VARCHAR), y actualicé el caché, sin embargo, no funciona. En la base de datos ramained VARCHAR (25) pero en Drupal, el campo tiene el mismo valor de tamaño máximo que antes 10. ¿Tal vez hay alguna configuración de campo oculto?
Ek Kosmos