Wie entferne ich ein Feld programmgesteuert von einem Knoten?

16

Wie entfernt man ein Feld programmgesteuert von einem Knoten? Ich habe eine Migration hook_update_N, die den Inhalt von einem Feld in eine benutzerdefinierte Tabelle verschiebt. Nach dieser Migration möchte ich das Feld in derselben Funktion entfernen.

Gibt es Feld-APIs, die das Entfernen von Feldern ermöglichen?

Bearbeiten, Lösung : Da den Antworten aktueller Code fehlt, habe ich die Felder aus den $ -Nutzern in meine eigenen Datensätze verschoben und sie anschließend aus der Datenbank entfernt.

function my_module_update_7005(&$sandbox) {
  $slice = 100;
  //Fetch users from database;
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['current_uid'] = 0;
    // We'll -1 to disregard the uid 0...
    $sandbox['max'] = db_query('SELECT COUNT(DISTINCT uid) FROM {users}')->fetchField() - 1;
  }
  if (empty($users)) {
    $sandbox["current_uid"] += $slice;
  }
  $users = db_select('users', 'u')
    ->fields('u', array('uid', 'name'))
    ->condition('uid', $sandbox['current_uid'], '>')
    ->range(0, $slice)
    ->orderBy('uid', 'ASC')
    ->execute();
  //Loop trough users;
  foreach ($users as $user) {
    $foo = new Foo();
    // Warning: drupal's fields return mixed values; e.g. NULL versus an int.
    $foo->debits = (int) $user->user()->field_credits["und"][0]["value"];
    $foo->save();

    $sandbox['progress']++;
    $sandbox['current_uid'] = $user->uid;
  }

  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);

  // Remove the field.
  field_delete_field("field_credits"); //note that the name for Foo is field_foo
  field_purge_batch($sandbox['max']+1);//Drupal seems to have an offbyone problem.
}
Berkes
quelle

Antworten:

29

field_delete_field($field_name)markiert das $field_namezum Löschen beim nächsten Cron-Lauf.

Sie können field_purge_batchden Löschvorgang ausführen, wenn Sie dies nicht im Cron Run tun möchten.

BEARBEITEN: field_delete_field() sollte verwendet werden, wenn Sie das Feld auch aus anderen Bündeln löschen müssen. Wenn Sie das Feld nur aus einem bestimmten Bundle löschen möchten, sollten Sie es field_delete_instance()wie von @Clive erwähnt verwenden.

Ajits
quelle
4
Vorsicht, die auch das Feld von anderen Bundles entfernen wird es :) Gut angebracht sein könnte zu wissen , über field_purge_batchobwohl
Clive
@Clive: Richtig, es löscht das Feld aller Bündel. Vielen Dank für die Korrektur :) Ich habe die Antwort bearbeitet.
Ajits
Ich wollte das Feld komplett entfernen, dh von allen Bündeln. Aber die Warnung ist gut. Vielen Dank.
Berkes
1
field_delete_instance () ist der richtige Weg.
Ryan McVeigh
field_purge_batch () löscht tatsächlich nur so viele Feldelemente wie die Stapelgröße, die an es übergeben wird. Dies kann hilfreich sein, wenn das Feld nur wenige Elemente enthält. Um die Feldinstanz vollständig zu entfernen, müssen Sie nicht warten, bis cron sie bereinigt hat. Wenn Sie viele Werte im Feld haben, sollten Sie nicht versucht sein, die Chargengröße zu hoch zu setzen (das "Batch" im Namen bedeutet nicht, dass es selbst Batches ausführt, sondern nur, dass es eine einzelne Charge ausführt von so vielen Gegenständen, wie Sie verlangen); Sie könnten auf PHP-Speicher oder Zeitlimits stoßen.
Eelke Blok
24

Um ein Feld aus einem bestimmten Bündel zu entfernen, können Sie verwenden field_delete_instance()

Markiert eine Feldinstanz und ihre Daten zum Löschen.

Beispiel:

function my_module_update_7001() {
  if ($instance = field_info_instance('node', 'field_name', 'page'))  {
    field_delete_instance($instance, TRUE);
    field_purge_batch(1);
  }
}

Um ein Feld vollständig aus dem System zu entfernen, können Sie verwenden field_delete_field()

Markiert ein Feld und seine Instanzen und Daten zum Löschen.

Beispiel:

function my_module_update_7001() {
  field_delete_field('field_name');
  field_purge_batch(1);
}

Die Felder / Instanzen sind nur zum Löschen markiert, die Daten werden bei nachfolgenden Cron-Läufen tatsächlich gelöscht. So löschen Sie es manuell:

field_purge_batch(1);
Clive
quelle
1
Während des Anrufs field_delete_field()und der field_purge_batch()Arbeit werden Aufzeichnungen in field_config_instanceund geführt field_config. Warum das?
Berkes
Ich verstehe nicht ganz, warum der Aufruf von field_purge_batch mit dem Wert 1 alle Felddaten entfernt. Wenn ich den Code richtig verstehe, werden die Felddaten für $ batchsize-Entitäten abgerufen und dabei belassen (dh die Funktion wird nicht rekursiv aufgerufen oder so). Es scheint, als ob es an dem Anrufer liegt, zu prüfen, ob alle Daten weg sind, und wenn nicht, die Funktion weiter aufzurufen. Aber vielleicht verstehe ich etwas grundlegend falsch.
Eelke Blok
Dieser Kommentar in field_ui.admin.inc erklärt Folgendes: // Felder werden auf cron gelöscht. Das Feldmodul // verhindert jedoch, dass Module deaktiviert werden, wenn die von ihnen bereitgestellten Feldtypen in einem Feld // verwendet werden, bis es vollständig gelöscht ist. In dem Fall, dass ein Feld nur minimalen oder gar keinen Inhalt hat, wird es durch einen // einzelnen Aufruf von field_purge_batch () aus dem System entfernt. Rufen Sie dies mit einer // niedrigen Stapelbegrenzung auf, um zu vermeiden, dass Administratoren auf Cron-Läufe warten müssen, wenn // Instanzen entfernt werden, die diese Kriterien erfüllen.
Eelke Blok
@Clive, ich vertraue darauf, dass Sie so ziemlich implizit beraten werden, aber ich kann nicht übersehen, wie komisch es für mich ist, eine Erklärung in einem if-Zustand zu haben. Ist das mit Absicht? Ich beziehe mich auf $instance = field_info_instance('node', 'field_name', 'page'). Sollte es nicht stattdessen sein $instance = field_info_instance('node', 'field_contact', 'job');und dann die if-Anweisung fallen lassen?
CDMO
1
@cdmo es heißt "Zuordnung in Bedingung", und ja, es hat Probleme . Aber Drupal Core nutzt es auch in der neuesten Version großzügig, so dass es zumindest Präzedenzfälle gibt. Um ehrlich zu sein, das war vor 5 Jahren und ich bin jetzt ein bisschen weiser. Entweder verwende ich es nicht oder, aus welchem ​​Grund auch immer, ich wickle den Auftrag ab (z. B. ist if ( ($foo = $bar) ) {die Absicht offensichtlich und das Potenzial) Die if-Anweisung selbst ist notwendig, weil field_delete_instancenicht auf null geprüft wird
Clive
5

Um @berkes Frage zu beantworten:

field_delete_field()markiert das Feld zum Löschen und löscht es beim nächsten Cron-Lauf. Allerdings macht es leave Daten über field_config_instancedas abgelegte Feld über. field_purge_batch()Wird cron ausgeführt oder werden diese Daten nicht aus der field_config_instanceTabelle entfernt, auch wenn die gelöschte Spalte 1für das Feld auf gesetzt ist.

Für mich hat das Verwenden von field_delete_instance()gefolgt von einem field_purge_batch()für jedes gelöschte Feld funktioniert - sowohl das Entfernen des Felds aus der Datenbank (ohne dass ein Cron erforderlich ist) als auch field_config_instancedas Löschen der Tabelle mit Felddaten (für das gelöschte Feld).

Hier ist die Lösung:

/**
 * Implements hook_uninstall().
 */
function hook_uninstall() {
  // Delete all fields for all xyz entity bundles.

  // Retrieve all bundles for an entity.
  $bundles = field_info_bundles('XYZ'); // The name of your entity type, for example, 'node'.
  foreach ($bundles as $bundle => $properties) {

    // Retrieve all the fields for a given bundle.
    $instances = field_info_instances('XYZ', $bundle);
    foreach ($instances as $instance) {
      field_delete_instance($instance, TRUE);
      field_purge_batch(1);
    }
  }
}

Sie beachten Sie die TRUEauf field_delete_instance(), da es zeigt , dass das Feld API Bereinigungen durchzuführen , sollte.

Amateur Barista
quelle
Wie benutze ich diesen Code? Ich möchte das Titelfeld aus einem Inhaltstyp löschen
Umair