Como alterar o tamanho das configurações de campo?

46

Eu defini uma vez para um site um limite de comprimento para um campo. E agora o cliente deseja colocar mais caracteres nesse campo.

Não consigo alterar o tamanho máximo do Drupal porque recebo a seguinte mensagem de erro:

Existem dados para este campo no banco de dados. As configurações de campo não podem mais ser alteradas.

No entanto, deve haver uma solução. Devo alterá-lo no banco de dados (o campo é implementado pelo módulo de coleções de campos )?

Ek Kosmos
fonte
Você pode nos dizer qual versão do Drupal e do CCK? Também existem módulos de contribuição CCK?
Patrick Patrick
A versão do Drupal é 7.
Ek Kosmos
E você não pode modificá-lo na seção gerenciar campos do tipo de conteúdo? Você deve poder modificá-lo a qualquer momento. Pode dar um aviso, mas ainda deve permitir. Isso pode ser um bug / limitação no módulo de coleções de campos.
Patrick
Você já tentou usar grupos de campos? Agora você pode fazer coisas como duplicação de grupo que não podia fazer antes.
Patrick
Não posso modificá-lo na seção de gerenciamento de campos do tipo de conteúdo! Essa é a questão. Drupal não me deixa fazer isso.
Ek Kosmos

Respostas:

89

A solução Dylan Tack é a mais fácil, mas pessoalmente gosto de explorar as alas internas do banco de dados do Drupal para ver como as coisas são gerenciadas lá em baixo.

Portanto, supondo que você tenha um campo de texto cujo nome da máquina seja field_text de 10 caracteres, você deseja aumentar para 25:

  • os dados serão armazenados em duas tabelas: field_data_field_text e field_revision_field_text
  • A definição é armazenada em field_config para os dados de armazenamento e field_config_instance para cada instância desse campo (como etiqueta).

Agora vamos fazer uma pequena cirurgia cardíaca.

  1. Altere as definições das colunas das tabelas de dados:

    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. Altere a coluna de definição , essa é muito complicada porque está armazenada em um BLOB , mas isso não é algo que o impedirá de fazer isso.

    • Dissecar as entranhas dessa coisa de BLOB :

    SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) 
    FROM `field_config` WHERE field_name = 'field_text';
    • Isso lhe 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 é uma matriz serializada PHP , a parte interessante é que s:10:"max_length";s:2:"10";isso significa que essa matriz possui uma propriedade denominada max_length(cujo nome é uma sequência de 10 caracteres - daí o "s") cujo valor é 10 (que é uma sequência de 2 caracteres). É bem fácil, não é?

    • Alterar seu valor é tão fácil quanto substituir a s:2:"10"peça s:2:"25". Cuidado: se o seu novo valor for maior, você precisará adaptar a parte "s", por exemplo, colocar 100 será o s:3:"100"comprimento de 100 ser 3.

    • Vamos colocar esse novo valor de volta no banco de dados, não esqueça de manter toda a string.

    UPDATE `field_config` 
    SET data = 'a:7:{...a:2:{s:10:"max_length";s:2:"25";...}'
    WHERE `field_name` = 'field_text'
    • Lave seus caches.
  3. ???

  4. LUCRO!

A propósito, o PhpMyAdmin possui algumas configurações para permitir a modificação direta de colunas BLOB , mas por que seguir o caminho mais fácil?

PS: Isso também pode salvar sua vida ao colocar algum código PHP em visualizações e obter um WSOD devido a um erro no seu código.

tostinni
fonte
Essa primeira instrução SQL deve dizer que ALTER TABLEnão SELECT TABLE. Além disso, você pode torná-lo mais limpo como: ALTER TABLE field_data_field_text MODIFY field_text_value... (MODIFY é como mudar quando você não quiser alterar o nome E você não..)
artfulrobot
4
Obrigado por isso. Eu gostaria de ter mais de um voto positivo para dar.
BC01 9/02/12
1
Este post usa API do esquema do Drupal para alcançar a mesma abordagem: up2technology.com/blog/converting-drupal-fields
Juampy NR
2
Se você não se importa de enviar os seus dados serializados para os internets, encontrei esta ferramenta, ótimo para a edição: pines.sourceforge.net/phpserialeditor.php
Pete
Se você receber um erro sobre 'CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL', você poderá usar o 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
fonte
Como essa correção, o máximo, já que não depende de hackery manual do banco de dados ... é essencial ter uma solução replicável via hook_update_N!
areynolds
9

Isso parece ser uma limitação do módulo de texto atual. text_field_settings_form () tem este comentário: " @todo : Se $ has_data, adicione um manipulador de validação que permita apenas que max_length aumente.".

Como solução temporária, você pode comentar '#disabled' => $has_dataem modules / field / modules / text / text.module, na linha 77.

Não foi possível encontrar um problema existente para este caso específico, mas você pode mencioná-lo no # 372330 .

Dylan Tack
fonte
2
Obrigado pela sua resposta. Eu comentei a linha e agora posso modificar o valor do campo, no entanto, recebo o seguinte erro após o sumbit:Attempt to update field Serial No failed: field_sql_storage cannot change the schema for an existing field with data..
Ek Kosmos
Em relação a cometer o problema drupal, vá em frente e faça-o.
Ek Kosmos
1
Não consegui fazer isso funcionar. Depois de comentar essa linha, ainda recebi um erro MYSQL que ALTER TABLE falhou.
jchwebdev 4/09/14
Se você receber um, FieldUpdateForbiddenException: cannot change the schema for an existing field with datatambém precisa comentar o L282 modules/field/modules/field_sql_storage/field_sql_storage.module.
dieuwe
O comentário de @ dieuwe está errado. Esse arquivo não existe nas versões recentes do D8 (se é que existiu). Você precisa comentar as duas linhas core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.phpque lançam exceções com o texto "O armazenamento SQL não pode alterar o esquema de um campo existente". Sobre as linhas 1312 e 1403.
Dalin 20/10
6

Drupal 7

Ao criar um campo de texto no Drupal 7, você deve escolher um comprimento máximo para seus dados. Assim que você cria dados para esse campo, o comprimento máximo se torna imutável nas configurações do campo Drupal.

É compreensível que isso seja desativado por diminuir o comprimento máximo, pois isso pode resultar em perda de dados; no entanto, deve ser possível aumentar o tamanho máximo de qualquer campo. Uma tarefa no código do módulo de texto Drupal 7 mostra que isso foi planejado, mas nunca realizado.

As 3 coisas que precisam acontecer:

  1. Altere o comprimento VARCHAR da coluna de valor na tabela field_data_ {fieldname}
  2. Altere o comprimento VARCHAR da coluna de valor na tabela field_revision_ {fieldname}
  3. Atualize a configuração do campo para refletir a nova configuração de comprimento máximo. A função a seguir realiza todas essas 3 etapas e executa 2 parâmetros fáceis, incluindo o nome do campo e o novo comprimento máximo.
/**
 * 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();
}

Quando essa função estiver disponível no seu arquivo de instalação personalizado, você poderá criar uma nova função de atualização do banco de dados que utilize essa nova função para fazer as alterações necessárias.

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

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


Drupal 8

Aqui está a versão da mesma função proposta 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
fonte
1
Usamos esse método drupal 8 em um projeto e encontramos problemas nos quais, quando você executava drush updb --entity-updatesos campos em que executamos essa função, seria marcado como exigindo uma atualização. Ele tentaria atualizar o esquema do campo novamente no mysql. Para nós, isso falharia, pois já havia dados de campo. Isso impedia a execução de outras tarefas de atualização.
Leon.nk
Para encurtar a história, provavelmente é mais seguro criar novos campos e migrar dados.
Leon.nk
3

Tente isso ... isso atualizará o tipo de dados do campo de TEXT para LONG_TEXT e atualizará max_lengthde 4000 para o tamanho máximo do texto longo ... espero que isso ajude.

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
fonte
3

D8

  1. Comente as duas linhas core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchem‌​a.phpque lançam exceções com o texto "O armazenamento SQL não pode alterar o esquema de um campo existente". Sobre as linhas 1312 e 1403.
  2. No seu navegador, navegue para /admin/config/development/configuration/single/export. O tipo de configuração é "Armazenamento em campo" e escolha o campo em questão. Copie a configuração.
  3. Navegue para /admin/config/development/configuration/single/import. . O tipo de configuração é "Armazenamento em campo". Cole a configuração. Mude o comprimento.
  4. Envie o formulário.

Observe (como você provavelmente já sabe), se você diminuir o tamanho, os dados existentes serão truncados.

Dalin
fonte
Isso funcionou como um encanto. No Drupal 8.5.3, as linhas são 1505-1507 na função protegida updateDedicatedTableSchema e 1596-1598 na função protegida updateSharedTableSchema. Certifique-se de voltar quando estiver pronto! Obrigado.
HongPong
Eu tentei essa abordagem pela primeira vez. Estou tentando modificar um campo de parágrafo. Funciona, mas mesmo assim é obrigatório ALTERAR as tabelas correspondentes.
Yaazkal 16/07/19
@Yaazkal Hmmm, essa não foi a minha experiência. Você está tentando aumentar ou diminuir o campo?
Dalin
@ Dalin aumenta, de 255 para 510. Usando D 8.5.5 e parágrafos 1.3
Yaazkal 16/07/19
1

No Drupal 7, fiz modificações em 2 tabelas no phpmyadmin e atualizei o cache.

  1. "field_data_field_lorem": alterado "field_lorem_value" para "longtext"
  2. "field_config": alterado "type" para "text_long"
Jill
fonte
Você enviou isso como um patch para o D7? Se esse é realmente o problema, você deve realmente emitir um patch para resolver esse problema no código principal.
Patrick
Alterei meu valor do tamanho do campo de phpmyadmin (de 10 para 25 do tipo VARCHAR) e atualizei o cache, no entanto, não está funcionando. No VARCHAR ramained do banco de dados (25), mas no Drupal, o campo tem o mesmo valor de tamanho máximo de antes de 10. Talvez haja alguma configuração de campo oculto?
Ek Kosmos