Ampliando el limite de caracteres de un campo de texto

4 minutos

En algunos artículos en internet este tema es explicado, incluso en la documentación de Drupal, pero la verdad es que no funcionan y lo peor en algunos de ellos se eliminan los datos del campo temporalmente para luego volver a cargarlos, proceso que es innecesario para este caso en particular.

También es importante entender que este proceso no se puede hacer por medio de la administración de Drupal cuando el campo ya tiene datos, lo verás deshabilitado con un mensaje como se muestra a continuación:

Field Length disabled

El código para esto lo debes poner en un archivo con extensión .install, que según el nombre de tu módulo quedaría así nombre-del-modulo.install.

A continuación te mostraré como queda el contenido de este archivo, el cual logre entendiendo las cosas que hacen bien en algunos ejemplos de código y mejorándolo para producir correctamente el resultado que necesitamos.

<?php

/**
 * @file
 * Install hooks.
 */

use Drupal\field\Entity\FieldStorageConfig;

/**
 * Increase field caption length.
 */
function nara_image_caption_update_9001() {
  db_change_varchar_field('media', 'field_caption', 500);
}

/**
 * Change length of a varchar entity field with data, safe with entity-updates.
 *
 * This updates the storage schema, the database schema, and the last
 * installed schema.
 *
 * The entity schema must also be changed in code in the entities
 * baseFieldDefinitions() or in an alter.
 *
 * @param string $entity_type_id
 *   The entity type.
 * @param string $field_name
 *   The field name to change.
 * @param int $new_length
 *   The new length of the field, must be larger than the previous value.
 */
function db_change_varchar_field($entity_type_id, $field_name, $new_length) {
  // Update Storage Schema.
  $storage_key = $entity_type_id . '.field_schema_data.' . $field_name;
  $storage_schema = \Drupal::keyValue('entity.storage_schema.sql');
  $field_schemas = $storage_schema->get($storage_key);
  foreach ($field_schemas as &$field_schema) {
    $field_schema['fields'][$field_name . '_value']['length'] = $new_length;
  }
  $storage_schema->set($storage_key, $field_schemas);

  // Updating db fields.
  $db = Drupal::database();
  foreach ($field_schemas as $table_name => $table_schema) {
    $db->schema()->changeField($table_name, $field_name . '_value', $field_name . '_value', $table_schema['fields'][$field_name . '_value']);
  }

  // Update field configuration.
  $config = \Drupal::configFactory()
    ->getEditable('field.storage.' . $entity_type_id . '.' . $field_name);
  $config->set('settings.max_length', $new_length);
  $config->save(TRUE);

  // Update field storage configuration.
  FieldStorageConfig::loadByName($entity_type_id, $field_name)->save();
}

Ahora viene la explicación de lo que está pasando aquí.

Usando el hook_update_N

Este es el hook que se usa para actualizar partes del sitio usando código y cada actualización se va numerando de manera incremental, para este ejemplo asumimos que es la primera actualización hecha por este módulo, por lo que usamos el número 9001, la norma para esta numeración se explica aquí drupal.org

lo único que estamos haciendo en este hook es usar la función db_change_varchar_field que se encarga de actualizar el campo, que como ves en este caso es uno llamado field_caption en el tipo de entidad media, y se ampliara para soportar hasta 500 caracteres.

Para que estas actualizaciones se apliquen a tu sitio necesitas usar el siguiente comando de drush:

drush updatedb

Actualizando el esquema

// Update Storage Schema.
$storage_key = $entity_type_id . '.field_schema_data.' . $field_name;
$storage_schema = \Drupal::keyValue('entity.storage_schema.sql');
$field_schemas = $storage_schema->get($storage_key);
foreach ($field_schemas as &$field_schema) {
  $field_schema['fields'][$field_name . '_value']['length'] = $new_length;
}
$storage_schema->set($storage_key, $field_schemas);

El esquema con el que el campo fue creado queda guardado en la base de datos de Drupal utilizando el KeyValue API, esta información es utilizada por algunos servicios y lo que hacemos aquí es actualizar la longitud de la columna que contiene los valores.

Actualizando las columnas en la base de datos

// Updating db fields.
$db = Drupal::database();
foreach ($field_schemas as $table_name => $table_schema) {
  $db->schema()->changeField($table_name, $field_name . '_value', $field_name . '_value', $table_schema['fields'][$field_name . '_value']);
}

Ahora sí, pasamos a actualizar la base de datos y me refiero a columnas porque en muchos casos los campos tienen revisiones y esto genera una tabla más, así que actualizamos la columna que contiene los valores existentes en ambas tablas.

Actualizando configuración del campo

// Update field configuration.
$config = \Drupal::configFactory()
  ->getEditable('field.storage.' . $entity_type_id . '.' . $field_name);
$config->set('settings.max_length', $new_length);
$config->save(TRUE);

// Update field storage configuration.
FieldStorageConfig::loadByName($entity_type_id, $field_name)->save();

Desde Drupal 8 la definición de cada campo es una entidad de configuración, para así poder replicar la estructura de tus tipos de contenido en otros ambientes, lo que hacemos aquí es actualizar esa configuración y en la última línea volvemos a guardarla para que Drupal se actualice en todos los lugares donde esa configuración es usada.

Exportar la configuración

Por último, lo que debes hacer es exportar la configuración, para poder mover estos cambios a otros ambientes y también porque que si no lo haces perderás parte del trabajo al tratar de importar desde otro ambiente.

Conclusión

Aunque este proceso parece muy complejo, espero haberlo explicado de una manera sencilla y que esto también te sirva como punto de partida para otro tipo de actualizaciones, recuerda probar este código primero en un ambiente local habiendo hecho una copia de tu base de datos.

Jidrone Drupal Developer
J. Ivan Duarte
Drupal Senior Developer

Share