Feldeinstellungen nachträglich ändern trotz vorhandener Daten

In Drupal ist es nicht möglich, bestimmte Einstellungen eines Feldes nachträglich zu ändern, wenn sich bereits Daten in diesem Feld befinden. Und das aus gutem Grund: Während der Erstellung eines neuen Feldes, werden entsprechende Datenbank-Tabellen (basierend auf den gemachten Einstellungen) angelegt. Bestimmte Änderungen an diesen Einstellungen, hätten aber aber die Tabellen mit einem anderen Schema generiert. Deshalb können genau diese Optionen nachträglich nicht per Field UI mehr geändert werden.

Zu erkennen sind diese Felder daran, dass sie in dem Formular für die Feldeinstellungen deaktiviert sind.

Je nach Feldtyp (und abhängig von installierten Modulen) sind die geschützen Einstellungen sehr unterschiedlich.

Feldeinstellungen nachträglich ändern

Neben der Möglichkeit, das Feld zu löschen und neu anzulegen (dabei werden aber alle enthaltenden Daten gelöscht!) ist, die Änderungen programmatisch über eine Update-Funktion durchzuführen. Hierbei werden die geänderten Einstellungen quasi direkt in die Datenbank geschrieben und evtl. Datenbankschema-Anpassungen direkt durchgeführt.

Bei manchen Einstellungen gehen die Änderungen recht unkompliziert. Manch andere sind wesentlich aufwendiger. Hierbei muss immer wieder getestet werden und es gleicht einer Detektivarbeit, die benötigten Anpassungen zu extrahieren und per Update-Funktion „nachzubauen“.

Die Vorgehensweise ist meist:

  • Versucht gar nicht erst, diese Änderungen an der Live-Website zu erledigen. Habe immer ein Backup und teste die Änderung und Update-Routine immer er lokal. Ansonsten beschwere dich bitte nicht über Datenverlust.
  • Lade die aktuellen Feldeinstellungen aus der Datenbank (db_query() das Feld aus der {field_config} Tabelle.
    • Da die Felddaten serialisiert gespeichert sind, musst du unserialize() nutzen, um sie in ein Array umzuwandeln.
    • Schau dir den Aufbau an und identifiziere die Array-Keys, die du anpassen möchtest.
    • Ändere die entsprechenden Key/Values in dem Array.
    • Serialize() das Array zurück und schreibe es zurück in die Datenbank (db_update()).
  • Je nach Änderungen, muss noch das Tabellen-Schema des Feldes angepasst werden (nutze hier db_add_field() oder db_drop_field() auf die entsprechende Feld data und revisions Tabellen.
  • Tipp: Es hilft, die benötigten Änderungen leichter zu identifizieren, wenn du …
    • ein neues Feld mit den gewünschten Einstellungen anlegst,
    • mit fieldreadfield() die Einstellungen die ausgeben lässt und das gleiche mit dem bisherigen Feld machst,
    • anhand der beiden Ausgaben, lassen sich die Unterschiede schnelle identifizieren.
    • Zudem kannst du die beiden Datenbanktabellen (der Felder) vergleichen und so entsprechende Änderungen erkennen.
    • Wenn du die für deine Einstellungen benötigten Änderungen identifiziert hast, musst du diese per PHP Update-Funktion nachbauen.
  • Manchmal ist es auch einfacher, einfach ein neues Feld anzulegen und den bestehenden Inhalt zu migrieren.

Beispiel: Datumsfeld (Date Module) nachträglich wiederholbar machen

In dem folgden Beispiel haben wir ein Datumsfeld (aus dem Date Modul) und möchten dort nun nachträglich die Option „Repeating Date“ aktivieren. Da dies ein nachträglicher Kundenwunsch ist, konnten wir diese Option nicht gleich am Anfang aktivieren.

Mit der folgenden Update Routine lässt sich jetzt diese Änderung auf der Datenbank durchführen (siehe hook_update_N):

function MYMODULE_update_7101() {
  // Activate the required modules.
  module_enable(array('date_repeat', 'date_repeat_field'));
 
  $field_name = 'field_event_date';
 
  // Add the new (for date_repeat_field required) rrule column to the field database tables.
  $db_column_rrule = array(
    'type' => 'text',
    'not null' => FALSE,
    'sortable' => FALSE,
    'views' => FALSE,
  );
  db_add_field('field_data_' . $field_name, $field_name . '_rrule', $db_column_rrule);
  db_add_field('field_revision_' . $field_name, $field_name . '_rrule', $db_column_rrule);
 
  // Load the field information.
  $field = db_query('SELECT data FROM {field_config} WHERE field_name = :field_name', array(':field_name' => $field_name))->fetchAssoc();
  $field = isset($field['data']) ? unserialize($field['data']) : FALSE;
 
  // Change the field setting.
  $field['settings']['repeat'] = 1;
 
  // Save the field change.
  $serialized_field = serialize($field);
  db_update('field_config')
    ->fields(array('data' => $serialized_field))
    ->condition('field_name', $field_name)
    ->execute();
 
  // Clear caches
  field_cache_clear(TRUE);
}

Je nachdem wir das Feld bisher aussah, muss in unserem Szenario noch die Anzahl der Werten auf „unlimited“ gesetzt werden. Dies haben wir über eine Änderung in dem entsprechenden Feature durchgeführt.