Wie ändere ich die Länge der Feldeinstellungen?

46

Ich habe einmal für eine Website eine Längenbeschränkung für ein Feld festgelegt. Und jetzt möchte der Kunde mehr Zeichen in dieses Feld einfügen.

Ich kann die maximale Größe von Drupal nicht ändern, da die folgende Fehlermeldung angezeigt wird:

Es gibt Daten für dieses Feld in der Datenbank. Die Feldeinstellungen können nicht mehr geändert werden.

Es muss jedoch eine Lösung geben. Soll ich es in der Datenbank ändern (das Feld ein durch die implementierten Feld Sammlungen Modul)?

Ek Kosmos
quelle
Können Sie uns sagen, welche Version von Drupal und CCK? Auch irgendwelche CCK Contrib Module?
Patrick
Drupal-Version ist 7.
Ek Kosmos
Und Sie können es nicht im Abschnitt zum Verwalten von Feldern für den Inhaltstyp ändern? Sie sollten es jederzeit ändern können. Es könnte Ihnen eine Warnung geben, aber es sollte es trotzdem zulassen. Dies kann ein Fehler / eine Einschränkung im Feldsammlungsmodul sein.
Patrick
Haben Sie versucht, Feldgruppen zu verwenden? Sie können jetzt Dinge wie das Duplizieren von Gruppen ausführen, die Sie vorher nicht konnten.
Patrick
Ich kann es nicht im Abschnitt zum Verwalten von Feldern für den Inhaltstyp ändern! Das ist der Punkt. Drupal lass es mich nicht tun.
Ek Kosmos

Antworten:

89

Die Lösung von Dylan Tack ist die einfachste, aber ich persönlich erkunde gerne die inneren Bereiche der Datenbank von Drupal, um zu sehen, wie die Dinge dort unten verwaltet werden.

Angenommen, Sie haben ein Textfeld, dessen Computername aus 10 Zeichen besteht, die Sie auf 25 erweitern möchten:

  • Die Daten werden in zwei Tabellen gespeichert: field_data_field_text und field_revision_field_text
  • Die Definition wird in field_config für die Speicherdaten und field_config_instance für jede Instanz dieses Felds (z. B. label) gespeichert.

Jetzt machen wir eine kleine Herzoperation.

  1. Ändern Sie die Definitionen der Datentabellenspalten:

    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. Ändern Sie die Definitionsspalte . Diese Spalte ist sehr schwierig, da sie in einem BLOB gespeichert ist. Dies kann Sie jedoch nicht davon abhalten, dies zu tun.

    • Untersuchen Sie die Eingeweide dieser BLOB- Sache:

    SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) 
    FROM `field_config` WHERE field_name = 'field_text';
    
    • Dies gibt Ihnen etwas wie:

    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...
    
    • Dies ist ein mit PHP serialisiertes Array. Der interessante Teil ist s:10:"max_length";s:2:"10";, dass dieses Array eine benannte Eigenschaft hat max_length(der Name ist eine 10-stellige Zeichenfolge - daher das "s"). Der Wert ist 10 (die eine 2-stellige Zeichenfolge ist). Es ist ziemlich einfach, nicht wahr?

    • Das Ändern des Werts ist so einfach wie das Ersetzen des s:2:"10"Teils durch s:2:"25". Seien Sie vorsichtig: Wenn Ihr neuer Wert länger ist, müssen Sie den "s" -Teil anpassen. Wenn Sie beispielsweise 100 eingeben, ist s:3:"100"100 gleich 3.

    • Setzen wir diesen neuen Wert in die DB zurück und vergessen Sie nicht, den gesamten String beizubehalten.

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

  4. PROFITIEREN!

PhpMyAdmin hat übrigens einige Einstellungen, mit denen BLOB-Spalten direkt geändert werden können , aber warum sollten Sie den einfachen Weg wählen ?

PS: Dies kann Ihnen auch das Leben retten, wenn Sie PHP-Code in Views einfügen und aufgrund eines Fehlers in Ihrem Code eine WSOD erhalten.

tostinni
quelle
Diese erste SQL-Anweisung sollte ALTER TABLEnicht heißen SELECT TABLE. Sie können es auch sauberer machen wie: ALTER TABLE field_data_field_text MODIFY field_text_value... (ÄNDERN ist wie ÄNDERN, wenn Sie den Namen nicht ändern möchten . Und Sie tun es nicht.)
artfulrobot
4
Danke dafür. Ich wünschte, ich hätte mehr als eine Gegenstimme.
BC01
1
Dieser Beitrag verwendet die Schema-API von Drupal, um denselben Ansatz zu erreichen: up2technology.com/blog/converting-drupal-fields
Juampy NR
2
Wenn es Ihnen nichts ausmacht, Ihre serialisierten Daten an das Internet zu senden, fand ich dieses Tool großartig zum Bearbeiten: pines.sourceforge.net/phpserialeditor.php
Pete
Wenn Sie eine Fehlermeldung zu 'CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL' erhalten, können Sie PhpMyAdmin verwenden.
22.
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
quelle
Wie dieses Update am häufigsten, da es nicht auf manuellem DB-Hackery basiert ... eine replizierbare Lösung über ein hook_update_N ist unerlässlich!
Areynolds
9

Dies scheint eine Einschränkung des aktuellen Textbausteins zu sein. text_field_settings_form () hat folgenden Kommentar: " @todo : Wenn $ has_data, fügen Sie einen Validate-Handler hinzu, der nur eine Erhöhung von max_length zulässt."

Als vorübergehende Problemumgehung können Sie '#disabled' => $has_datain modules / field / modules / text / text.module in Zeile 77 einen Kommentar abgeben.

Ich konnte kein vorhandenes Problem für diesen speziellen Fall finden, aber Sie könnten es auf # 372330 erwähnen .

Dylan Tack
quelle
2
Danke für deine Antwort. Ich habe die Zeile kommentiert und jetzt kann ich den Wert aus dem Feld ändern, jedoch erhalte ich nach sumbit die folgende Fehlermeldung:Attempt to update field Serial No failed: field_sql_storage cannot change the schema for an existing field with data..
Ek Kosmos
Wenn Sie sich für das Drupal-Problem interessieren, machen Sie es bitte.
Ek Kosmos
1
Ich konnte das nicht zum Laufen bringen. Nachdem ich diese Zeile kommentiert habe, habe ich immer noch einen MYSQL-Fehler erhalten, bei dem ALTER TABLE fehlgeschlagen ist.
Jchwebdev
Wenn Sie eine bekommen, müssen FieldUpdateForbiddenException: cannot change the schema for an existing field with dataSie auch L282 auskommentieren modules/field/modules/field_sql_storage/field_sql_storage.module.
Dieuwe
@ dieuwes Kommentar ist falsch. Diese Datei ist in neueren Versionen von D8 nicht vorhanden (falls dies jemals der Fall war). Sie müssen die beiden Zeilen in core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.phpdiesen Ausnahmebedingungen mit dem Text "Der SQL-Speicher kann das Schema für ein vorhandenes Feld nicht ändern" auskommentieren. Über die Linien 1312 und 1403.
Dalin
6

Drupal 7

Wenn Sie ein Textfeld in Drupal 7 erstellen, müssen Sie eine maximale Länge für Ihre Daten festlegen. Sobald Sie Daten für dieses Feld erstellen, wird die maximale Länge in den Drupal-Feldeinstellungen unveränderlich.

Es ist verständlich, dass dies deaktiviert ist, um die maximale Länge zu verringern, da dies zu einem Datenverlust führen kann. Es sollte jedoch möglich sein, die maximale Länge für jedes Feld zu erhöhen. Eine Aufgabe im Code des Drupal 7-Textmoduls zeigt, dass dies beabsichtigt, aber nie erreicht wurde.

Die 3 Dinge, die passieren müssen:

  1. Ändern Sie die VARCHAR-Länge der Wertspalte in der Tabelle field_data_ {fieldname}
  2. Ändern Sie die VARCHAR-Länge der Wertspalte in der Tabelle field_revision_ {fieldname}
  3. Aktualisieren Sie die Konfiguration des Felds, um die neue Einstellung für die maximale Länge widerzuspiegeln. Die folgende Funktion führt alle drei dieser Schritte aus und verwendet zwei einfache Parameter, einschließlich des Feldnamens und der neuen maximalen Länge.
/**
 * 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();
}

Sobald diese Funktion in Ihrer benutzerdefinierten Installationsdatei verfügbar ist, können Sie eine neue Datenbankaktualisierungsfunktion erstellen, die diese neue Funktion verwendet, um die erforderlichen Änderungen vorzunehmen.

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

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


Drupal 8

Hier ist die von @Christopher vorgeschlagene Version derselben Funktion :

/**
 * 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
quelle
1
Wir haben diese Drupal 8-Methode in einem Projekt verwendet und sind auf Probleme gestoßen, bei denen drush updb --entity-updatesdie Felder, die wir mit dieser Funktion durchlaufen haben, als aktualisierungsbedürftig markiert wurden. Es würde dann versuchen, das Feldschema in mysql erneut zu aktualisieren. Für uns würde dies dann scheitern, da dort bereits Felddaten vorhanden waren. Dies verhinderte die Ausführung anderer Update-Aufgaben.
leon.nk
Kurz gesagt, es ist wahrscheinlich sicherer, neue Felder zu erstellen und Daten zu migrieren.
leon.nk
3

Versuchen Sie dies ... dies aktualisiert den Felddatentyp von TEXT auf LONG_TEXT und die maximale Textlänge max_lengthvon 4000 auf 4000. Ich hoffe, dies hilft.

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

D8

  1. Kommentieren Sie die beiden Zeilen in core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchem‌​a.phpdiesen Ausnahmebedingungen mit dem Text "Der SQL-Speicher kann das Schema für ein vorhandenes Feld nicht ändern". Über die Linien 1312 und 1403.
  2. Navigieren Sie in Ihrem Browser zu /admin/config/development/configuration/single/export. Der Konfigurationstyp ist "Feldspeicher" und wählen Sie das betreffende Feld aus. Kopieren Sie die Konfiguration.
  3. Navigiere zu /admin/config/development/configuration/single/import. . Der Konfigurationstyp ist "Feldspeicher". Fügen Sie die Konfiguration ein. Ändern Sie die Länge.
  4. Senden Sie das Formular.

Beachten Sie (wie Sie wahrscheinlich bereits wissen), dass vorhandene Daten abgeschnitten werden, wenn Sie die Länge verkürzen.

Dalin
quelle
Das hat wie ein Zauber gewirkt. Ab Drupal 8.5.3 sind die Zeilen 1505-1507 in der geschützten Funktion updateDedicatedTableSchema und 1596-1598 in der geschützten Funktion updateSharedTableSchema. Stellen Sie sicher, dass Sie zurückwechseln, wenn es fertig ist! Danke.
Hongpong
Ich habe diesen Ansatz zuerst ausprobiert. Ich versuche, ein Absatzfeld zu ändern. Es funktioniert, aber es ist trotzdem zwingend erforderlich, die entsprechenden Tabellen zu ÄNDERN.
Yaazkal
@Yaazkal Hmmm, das war nicht meine Erfahrung. Versuchen Sie, das Feld zu verlängern oder zu verkürzen?
Dalin
@Dalin verlängern, von 255 auf 510. Unter Verwendung von D 8.5.5 und Paragraphen 1.3
Yaazkal
1

In Drupal 7 habe ich in phpmyadmin Änderungen an 2 Tabellen vorgenommen und den Cache aktualisiert.

  1. "field_data_field_lorem": "field_lorem_value" in "longtext" geändert
  2. "field_config": "type" in "text_long" geändert
Jill
quelle
Hast du das als Patch bei D7 eingereicht? Wenn dies wirklich das Problem ist, sollten Sie wirklich einen Patch für sie herausgeben, um dieses Problem im Kerncode zu beheben.
Patrick
Ich habe den Feldgrößenwert von phpmyadmin (von 10 auf 25 vom Typ VARCHAR) geändert und den Cache aktualisiert, aber es funktioniert nicht. In der Datenbank VARCHAR (25), aber in Drupal, hat das Feld die gleiche maximale Größe wie vor 10. Vielleicht gibt es eine Einstellung für versteckte Felder?
Ek Kosmos