Come modificare la lunghezza delle impostazioni del campo?


46

Ho impostato una volta su un sito Web un limite di lunghezza per un campo. E ora il cliente vuole mettere più caratteri in quel campo.

Non riesco a modificare la dimensione massima da Drupal perché viene visualizzato il seguente messaggio di errore:

Ci sono dati per questo campo nel database. Le impostazioni del campo non possono più essere modificate.

Tuttavia, ci deve essere una soluzione. Devo cambiarlo nel database (il campo è uno implementato dal modulo Field-collections )?


Puoi dirci quale versione di Drupal e CCK? Anche eventuali moduli contrib CCK?
Patrick,

La versione di Drupal è 7.
Ek Kosmos,

E non puoi modificarlo nella sezione di gestione dei campi del tipo di contenuto? Dovresti essere in grado di modificarlo in qualsiasi momento. Potrebbe darti un avvertimento, ma dovrebbe comunque consentirlo. Potrebbe trattarsi di un bug / limitazione nel modulo raccolte campi.
Patrick,

Hai provato a utilizzare i gruppi di campi? Ora puoi fare cose come la duplicazione di gruppo che prima non potevi.
Patrick,

Non posso modificarlo nella sezione di gestione dei campi del tipo di contenuto! Questo è il punto. Drupal non lasciarmi fare.
Ek Kosmos,

Risposte:


89

La soluzione di Dylan Tack è la più semplice, ma personalmente mi piace esplorare i reparti interni del database di Drupal per vedere come vengono gestite le cose laggiù.

Quindi, supponendo che tu abbia un campo di testo il cui nome macchina è field_text di 10 caratteri che vuoi aumentare a 25:

  • i dati verranno archiviati in due tabelle: field_data_field_text e field_revision_field_text
  • la definizione viene archiviata in field_config per i dati di archiviazione e field_config_instance per ogni istanza di questo campo (elementi come l'etichetta).

Ora facciamo un piccolo intervento al cuore.

  1. Modifica le definizioni delle colonne delle tabelle di dati:

    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. Cambia la colonna delle definizioni , questa è molto complicata perché è memorizzata in un BLOB , ma non è qualcosa che ti fermerà per farlo.

    • Sezionare l'intestino di questa cosa BLOB :

    SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) 
    FROM `field_config` WHERE field_name = 'field_text';
    • Questo ti darà qualcosa di simile:

    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...
    • Questo è un array serializzato PHP , la parte interessante è s:10:"max_length";s:2:"10";, questo significa che questo array ha una proprietà denominata max_length(il cui nome è una stringa di 10 caratteri - da qui la "s") il cui valore è 10 (che è una stringa lunga 2 caratteri). È abbastanza facile, no?

    • Modificare il suo valore è facile come sostituire la s:2:"10"parte con s:2:"25". Fai attenzione: se il tuo nuovo valore è più lungo devi adattare la parte "s", ad esempio mettendo 100 sarà s:3:"100"come 100 lunghezza è 3.

    • Rimettiamo questo nuovo valore nel DB, non dimenticate di mantenere l'intera stringa.

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

  4. PROFITTO!

A proposito, PhpMyAdmin ha alcune impostazioni per consentire la modifica diretta delle colonne BLOB , ma perché andare nel modo più semplice?

PS: Questo può anche salvarti la vita quando metti un po 'di codice PHP nelle viste e ottieni un WSOD a causa di un errore nel tuo codice.


Quella prima istruzione SQL dovrebbe dire ALTER TABLEno SELECT TABLE. Inoltre, puoi renderlo più pulito come: ALTER TABLE field_data_field_text MODIFY field_text_value... (MODIFICARE è come CAMBIA quando non vuoi cambiare il nome . E non lo fai.)
artfulrobot

4
Grazie per questo. Vorrei avere più di un voto da dare.
BC01,

1
Questo post utilizza l'API Schema di Drupal per ottenere lo stesso approccio: up2technology.com/blog/converting-drupal-fields
Juampy NR,

2
Se non ti dispiace inviare i tuoi dati serializzati a Internet, ho trovato questo strumento, ottimo per l'editing: pines.sourceforge.net/phpserialeditor.php
Pete

Se viene visualizzato un errore relativo a "SET DI CARATTERI utf8 COLLATE utf8_general_ci NULL DEFAULT NULL", è possibile utilizzare 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));
}

Ti piace di più questa correzione poiché non si basa sull'hacking DB manuale ... avere una soluzione replicabile tramite hook_update_N è essenziale!
areynolds

9

Questo sembra essere un limite del modulo di testo corrente. text_field_settings_form () ha questo commento: " @todo : se $ has_data, aggiungi un gestore validato che consenta solo di aumentare max_length.".

Come soluzione temporanea, è possibile commentare '#disabled' => $has_datain moduli / campo / moduli / testo / testo.module, intorno alla linea 77.

Non sono riuscito a trovare un problema esistente per questo caso specifico, ma potresti menzionarlo su # 372330 .


2
Grazie per la tua risposta. Ho commentato la riga e ora posso modificare il valore dal campo, tuttavia dopo il sumbit ricevo il seguente errore:Attempt to update field Serial No failed: field_sql_storage cannot change the schema for an existing field with data..
Ek Kosmos,

Per quanto riguarda il fatto di commettere il problema di Drupal, vai avanti e fallo.
Ek Kosmos,

1
Non sono riuscito a farlo funzionare. Dopo aver commentato quella riga, ho ancora ricevuto un errore MYSQL che ALTER TABLE non è riuscito.
jchwebdev,

Se ne ricevi uno FieldUpdateForbiddenException: cannot change the schema for an existing field with datadevi anche commentare L282 su modules/field/modules/field_sql_storage/field_sql_storage.module.
dieuwe,

Il commento di @ dieuwe è sbagliato. Quel file non esiste nelle ultime versioni di D8 (se mai lo fosse). È necessario commentare le due righe core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.phpche generano eccezioni con il testo "La memoria SQL non può modificare lo schema per un campo esistente". Circa le linee 1312 e 1403.
Dalin,

6

Drupal 7

Quando crei un campo di testo in Drupal 7, devi scegliere una lunghezza massima per i tuoi dati. Non appena si creano dati per questo campo, la lunghezza massima diventa immutabile nelle impostazioni del campo Drupal.

È comprensibile che questo sia disabilitato per ridurre la lunghezza massima perché potrebbe comportare una perdita di dati, tuttavia, dovrebbe essere possibile aumentare la lunghezza massima per qualsiasi campo. Un todo nel codice del modulo di testo di Drupal 7 mostra che questo era previsto ma mai realizzato.

Le 3 cose che devono accadere:

  1. Modificare la lunghezza VARCHAR della colonna del valore nella tabella field_data_ {fieldname}
  2. Modificare la lunghezza VARCHAR della colonna del valore nella tabella field_revision_ {fieldname}
  3. Aggiorna la configurazione del campo in modo che rifletta la nuova impostazione della lunghezza massima La seguente funzione esegue tutti e 3 questi passaggi e accetta 2 semplici parametri tra cui il nome del campo e la nuova lunghezza massima.
/**
 * 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 questa funzione è disponibile nel file di installazione personalizzato, è possibile creare una nuova funzione di aggiornamento del database che utilizza questa nuova funzione per apportare le modifiche richieste.

/**
 * 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-ma maximum - length


Drupal 8

Ecco la versione della stessa funzione proposta da @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
    );
  }
}

1
Abbiamo utilizzato questo metodo drupal 8 su un progetto e abbiamo riscontrato problemi in base ai quali, quando si eseguivano drush updb --entity-updatesi campi che utilizzavamo questa funzione, venivano contrassegnati come richiedenti un aggiornamento. Tenterebbe quindi di aggiornare nuovamente lo schema dei campi in mysql. Per noi questo fallirebbe perché c'erano già dei dati sul campo. Ciò impediva l'esecuzione di altre attività di aggiornamento.
leon.nk,

Per farla breve, è probabilmente più sicuro creare nuovi campi e migrare i dati.
leon.nk,

3

Prova questo ... questo aggiornerà il tipo di dati del campo da TEXT a LONG_TEXT e aggiornerà max_lengthda 4000 a una lunghezza massima del testo ... spero che questo aiuti.

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);    
  }
}

3

D8

  1. Commenta le due righe core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchem‌​a.phpche generano eccezioni con il testo "La memoria SQL non può modificare lo schema per un campo esistente". Circa le linee 1312 e 1403.
  2. Nel tuo browser, vai a /admin/config/development/configuration/single/export. Il tipo di configurazione è "Archiviazione campo" e scegli il campo in questione. Copia la configurazione.
  3. Vai a /admin/config/development/configuration/single/import. . Il tipo di configurazione è "Archiviazione su campo". Incolla la configurazione. Cambia la lunghezza.
  4. Invia il modulo

Nota (come probabilmente già saprai), se accorcia la lunghezza, i dati esistenti verranno troncati.


Questo ha funzionato come un fascino. A partire da Drupal 8.5.3 le linee sono 1505-1507 nell'aggiornamento della funzione protetta DedicatedTableSchema e 1596-1598 nell'aggiornamento della funzione protetta SharedTableSchema. Assicurati di tornare indietro al termine! Grazie.
HongPong,

Ho provato per la prima volta questo approccio. Sto cercando di modificare un campo di paragrafo. Funziona ma è comunque obbligatorio ALTER le tabelle corrispondenti.
Yaazkal,

@Yaazkal Hmmm, non è stata la mia esperienza. Stai cercando di allungare o accorciare il campo?
Dalin,

@Dalin allunga, da 255 a 510. Usando D 8.5.5 e paragrafi 1.3
Yaazkal,

1

In Drupal 7, ho apportato modifiche a 2 tabelle in phpmyadmin e ho aggiornato la cache.

  1. "field_data_field_lorem": modificato "field_lorem_value" in "longtext"
  2. "field_config": modificato "type" in "text_long"

Hai inviato questo come patch a D7? Se questo è davvero il problema, dovresti davvero emetterne una patch per risolvere questo problema nel codice principale.
Patrick,

Ho cambiato il mio valore della dimensione del campo da phpmyadmin (da 10 a 25 di tipo VARCHAR) e ho aggiornato la cache, tuttavia non funziona. Nel database ottenuto VARCHAR (25) ma in Drupal, il campo ha lo stesso valore di dimensione massima rispetto a 10. Forse c'è qualche impostazione di campo nascosta?
Ek Kosmos,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.