Jak zmienić długość ustawień pola?

46

Ustawiłem kiedyś na stronie internetowej limit długości pola. A teraz klient chce umieścić więcej znaków w tym polu.

Nie mogę zmienić maksymalnego rozmiaru z Drupala, ponieważ pojawia się następujący komunikat o błędzie:

W tym polu znajdują się dane dla tego pola. Ustawienia pola nie mogą być już zmieniane.

Jednak musi być rozwiązanie. Czy powinienem to zmienić w bazie danych (pole jest zaimplementowane przez moduł Field-collections )?

Ek Kosmos
źródło
Czy możesz nam powiedzieć, która wersja Drupal i CCK? Również jakieś moduły CCK?
Patrick,
Wersja Drupala to 7.
Ek Kosmos
Nie możesz go zmodyfikować w sekcji zarządzania polami typu zawartości? Powinieneś być w stanie zmodyfikować go w dowolnym momencie. Może dać ostrzeżenie, ale nadal powinno na to pozwalać. Może to być błąd / ograniczenie w module kolekcji terenowych.
Patrick,
Czy próbowałeś używać grup pól? Możesz teraz wykonywać takie czynności, jak powielanie grup, czego wcześniej nie mogłeś.
Patrick,
Nie mogę go modyfikować w sekcji zarządzania polami typu zawartości! O to chodzi. Drupal, nie pozwól mi tego zrobić.
Ek Kosmos,

Odpowiedzi:

89

Rozwiązanie Dylan Tack jest najłatwiejsze, ale osobiście lubię odkrywać wewnętrzne totemy bazy danych Drupala, aby zobaczyć, jak tam są zarządzane.

Zakładając, że masz pole tekstowe, którego nazwa maszyny to tekst_tekstowy zawierający 10 znaków, które chcesz zwiększyć do 25:

  • dane będą przechowywane w dwóch tabelach: field_data_field_text i field_revision_field_text
  • definicja jest przechowywana w field_config dla danych do przechowywania, a field_config_instance dla każdego wystąpienia tego pola (np. etykieta).

Teraz zróbmy małą operację serca.

  1. Zmień definicje kolumn tabel danych:

    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. Zmień kolumnę definicji , ta jest bardzo trudna, ponieważ jest przechowywana w BLOBIE , ale to nie jest coś, co powstrzyma cię przed zrobieniem tego.

    • Wnikliwie wnętrzności tym BLOB rzeczy:

    SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) 
    FROM `field_config` WHERE field_name = 'field_text';
    • To da ci coś takiego:

    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...
    • Jest to szeregowa tablica PHP , co ciekawe s:10:"max_length";s:2:"10";, oznacza to, że tablica ma właściwość o nazwie max_length(której nazwa to ciąg 10 znaków - stąd „s”), której wartość wynosi 10 (czyli ciąg 2 znaków). To całkiem proste, prawda?

    • Zmiana jego wartości jest tak prosta, jak wymiana s:2:"10"części przez s:2:"25". Uważaj: jeśli twoja nowa wartość jest dłuższa, musisz dostosować część „s”, na przykład wstawienie 100 będzie równe 100, s:3:"100"gdy długość wynosi 3.

    • Umieśćmy tę nową wartość z powrotem w DB, nie zapomnij zachować całego łańcucha.

    UPDATE `field_config` 
    SET data = 'a:7:{...a:2:{s:10:"max_length";s:2:"25";...}'
    WHERE `field_name` = 'field_text'
    • Opróżnij swoje skrzynki.
  3. ???

  4. ZYSK!

Nawiasem mówiąc, PhpMyAdmin ma pewne ustawienia pozwalające na bezpośrednią modyfikację kolumn BLOB , ale dlaczego iść w prosty sposób?

PS: Może to również uratować Ci życie, gdy umieszczasz jakiś kod PHP w widokach i otrzymujesz WSOD z powodu błędu w kodzie.

tostinni
źródło
Ta pierwsza instrukcja SQL powinna powiedzieć „ ALTER TABLEnie” SELECT TABLE. Możesz też uczynić go czystszym, jak: ALTER TABLE field_data_field_text MODIFY field_text_value... (MODYFIKUJ jest jak ZMIANA, gdy nie chcesz zmieniać nazwy . A ty nie.)
artfulrobot
4
Dzięki za to. Chciałbym mieć więcej niż jeden głos do wyrażenia.
BC01
1
W tym poście wykorzystano interfejs API schematu Drupala w celu osiągnięcia tego samego podejścia: up2technology.com/blog/converting-drupal-fields
Juampy NR
2
Jeśli nie masz nic przeciwko wysyłaniu zserializowanych danych do Internetu, znalazłem to narzędzie, idealne do edycji: pine.sourceforge.net/phpserialeditor.php
Pete
Jeśli pojawi się błąd dotyczący „ZESTAWU ZNAKÓW utf8 COLLATE utf8_general_ci NULL DEFAULT NULL”, możesz użyć 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
źródło
Najbardziej podobała mi się ta poprawka, ponieważ nie polega ona na ręcznym hakowaniu baz danych ... posiadanie replikowanego rozwiązania poprzez hook_update_N jest niezbędne!
areynolds
9

Wydaje się, że jest to ograniczenie bieżącego modułu tekstowego. text_field_settings_form () ma następujący komentarz: „ @todo : Jeśli $ has_data, dodaj poprawny moduł obsługi, który pozwala tylko na zwiększenie maksymalnej długości.”.

Aby tymczasowo obejść ten '#disabled' => $has_dataproblem, możesz komentować w module / field / modules / text / text.module, wokół linii 77.

Nie mogłem znaleźć istniejącego problemu dla tego konkretnego przypadku, ale możesz wspomnieć o nim na # 372330 .

Dylan Tack
źródło
2
Dzięki za odpowiedź. Skomentowałem wiersz i teraz mogę zmodyfikować wartość z pola, jednak po sumbit dostaję następujący błąd:Attempt to update field Serial No failed: field_sql_storage cannot change the schema for an existing field with data..
Ek Kosmos
Jeśli chodzi o popełnienie problemu drupala, proszę, zróbcie to.
Ek Kosmos
1
Nie mogłem tego uruchomić. Po skomentowaniu tego wiersza nadal występuje błąd MYSQL, który nie powiódł się ALTER TABLE.
jchwebdev
Jeśli otrzymasz, FieldUpdateForbiddenException: cannot change the schema for an existing field with datamusisz również skomentować L282 modules/field/modules/field_sql_storage/field_sql_storage.module.
dieuwe
Komentarz @ dieuwe jest nieprawidłowy. Ten plik nie istnieje w najnowszych wersjach D8 (jeśli kiedykolwiek miał). Musisz skomentować dwa wiersze w core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.phptym wyjątku wyrzucenia tekstem „Pamięć SQL nie może zmienić schematu dla istniejącego pola”. O liniach 1312 i 1403.
Dalin,
6

Drupal 7

Podczas tworzenia pola tekstowego w Drupal 7 musisz wybrać maksymalną długość danych. Po utworzeniu jakichkolwiek danych dla tego pola maksymalna długość staje się niezmienna w ustawieniach pola Drupal.

Zrozumiałe jest, że byłoby to wyłączone w celu zmniejszenia maksymalnej długości, ponieważ mogłoby to spowodować utratę danych, jednak powinno być możliwe zwiększenie maksymalnej długości dla dowolnego pola. Todo w kodzie modułu Drupal 7 Text pokazuje, że było to zamierzone, ale nigdy nie zostało osiągnięte.

3 rzeczy, które muszą się wydarzyć:

  1. Zmień długość VARCHAR kolumny wartości w tabeli field_data_ {fieldname}
  2. Zmień długość VARCHAR kolumny wartości w tabeli field_revision_ {fieldname}
  3. Zaktualizuj konfigurację pola, aby odzwierciedlić nowe ustawienie maksymalnej długości Poniższa funkcja wykonuje wszystkie 3 z tych kroków i przyjmuje 2 łatwe parametry, w tym nazwę pola i nową maksymalną długość.
/**
 * 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();
}

Gdy ta funkcja będzie dostępna w niestandardowym pliku instalacyjnym, możesz utworzyć nową funkcję aktualizacji bazy danych, która używa tej nowej funkcji do wprowadzenia wymaganych zmian.

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

Źródło: http://nathan.rambeck.org/blog/42-modify-drupal-7-text-field-maximum-length


Drupal 8

Oto wersja tej samej funkcji zaproponowanej przez @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
źródło
1
Zastosowaliśmy tę metodę drupal 8 w projekcie i napotkaliśmy problemy, w wyniku których po uruchomieniu drush updb --entity-updatespól, które przeszliśmy przez tę funkcję, oznaczono by jako wymagające aktualizacji. Następnie spróbuje ponownie zaktualizować schemat pola w mysql. Dla nas to się nie powiedzie, ponieważ były tam już dane z pola. Zapobiegało to uruchomieniu innych zadań aktualizacji.
leon.nk
Krótko mówiąc, prawdopodobnie bezpieczniej jest tworzyć nowe pola i migrować dane.
leon.nk
3

Spróbuj ... zaktualizuje to typ danych pola z TEKSTU na DŁUGI_TEKST i zaktualizuje max_lengthtekst z 4000 do maksymalnej długości tekstu ... mam nadzieję, że to pomoże.

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
źródło
3

D8

  1. Skomentuj dwa wiersze core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchem‌​a.phptego wyjątku z tekstem „Pamięć SQL nie może zmienić schematu dla istniejącego pola”. O liniach 1312 i 1403.
  2. W przeglądarce przejdź do /admin/config/development/configuration/single/export. Typ konfiguracji to „Pamięć pola” i wybierz odpowiednie pole. Skopiuj konfigurację.
  3. Przejdź do /admin/config/development/configuration/single/import. . Typ konfiguracji to „Storage Field”. Wklej konfigurację. Zmień długość.
  4. Prześlij formularz

Uwaga (jak zapewne już wiesz), jeśli skrócisz długość, istniejące dane zostaną obcięte.

Dalin
źródło
To działało jak urok. Od wersji Drupal 8.5.3 linie mają numery 1505-1507 w funkcji chronionej updateDedicatedTableSchema i 1596-1598 w funkcji chronionej updateSharedTableSchema. Pamiętaj, aby wrócić po zakończeniu! Dziękuję Ci.
HongPong,
Najpierw spróbowałem tego podejścia. Próbuję zmodyfikować pole akapitu. Działa, ale i tak jest obowiązkowe ZMIANA odpowiednich tabel.
Yaazkal,
@Yaazkal Hmmm, to nie było moje doświadczenie. Próbujesz wydłużyć lub skrócić pole?
Dalin
@Dalin wydłuża, z 255 do 510. Używając D 8.5.5 i akapitów 1.3
Yaazkal
1

W Drupal 7 dokonałem modyfikacji 2 tabel w phpmyadmin i odświeżyłem pamięć podręczną.

  1. „field_data_field_lorem”: zmieniono „field_lorem_value” na „longtext”
  2. „field_config”: zmieniono „type” na „text_long”
Jill
źródło
Czy przesłałeś to jako poprawkę do D7? Jeśli to jest naprawdę problem, powinieneś naprawdę wydać łatkę, aby rozwiązać ten problem w kodzie podstawowym.
Patrick,
Zmieniłem wartość wielkości pola z phpmyadmin (z 10 na 25 typu VARCHAR) i odświeżyłem pamięć podręczną, jednak nie działa. W bazie danych VARCHAR z ramami (25), ale w Drupal, pole ma taką samą maksymalną wielkość jak przed 10. Może jest jakieś ustawienie ukrytego pola?
Ek Kosmos