Jak programowo usunąć pole z węzła?

16

Jak programowo usunąć pole z węzła? Mam migrację, hook_update_Nktóra przenosi zawartość z pola do niestandardowej tabeli. Po tej migracji chcę usunąć pole w tej samej funkcji.

Czy są jakieś interfejsy API pól, które obsługują usuwanie pól?

Edycja, rozwiązanie : Ponieważ w odpowiedziach brakuje rzeczywistego kodu, oto co zrobiłem, aby przenieść pola od użytkowników $ do moich własnych rekordów, a następnie usunąć pole z bazy danych;

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

Odpowiedzi:

29

field_delete_field($field_name)zaznaczy $field_namedo usunięcia przy następnym uruchomieniu cron.

Możesz użyć field_purge_batchdo usunięcia, jeśli nie chcesz tego robić w trybie cron.

EDYCJA: field_delete_field() należy używać, gdy trzeba usunąć pole również z innych pakietów. Jeśli chcesz tylko usunąć pole z określonego pakietu, powinieneś użyć, field_delete_instance()jak wspomniano w @Clive.

AjitS
źródło
4
Ostrożnie, że będzie również usunąć pole z innych wiązek to może być związane z :) dobrze poznać field_purge_batchchoć
Clive
@Clive: tak, usunie pole ze wszystkich pakietów. Dziękujemy za poprawienie :) Zredagowałem odpowiedź.
AjitS,
Chciałem całkowicie usunąć pole, tj. Ze wszystkich pakietów. Ale ostrzeżenie jest dobre. Dzięki.
berkes
1
field_delete_instance () jest właściwą drogą.
Ryan McVeigh,
field_purge_batch () faktycznie usunie tylko tyle elementów pola, ile przekazany do niego rozmiar partii. Może to pomóc, gdy w polu jest tylko kilka elementów, aby całkowicie pozbyć się instancji pola, nie trzeba czekać na wyczyszczenie go przez crona. Jeśli masz wiele wartości w polu, nie kusz się, aby zbytnio zwiększyć wielkość partii („partia” w nazwie nie oznacza, że ​​sama wykona partię, oznacza to tylko, że wykona jedną partię tylu przedmiotów, ile o to poprosisz); możesz skończyć w pamięci PHP lub limitach czasowych.
Eelke Blok,
24

Aby usunąć pole z określonego pakietu, którego możesz użyć field_delete_instance()

Oznacza instancję pola i jej dane do usunięcia.

Przykład:

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

Aby całkowicie usunąć pole z systemu, możesz użyć field_delete_field()

Oznacza pole oraz jego instancje i dane do usunięcia.

Przykład:

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

Pola / instancje są zaznaczone tylko do usunięcia, dane zostaną faktycznie usunięte podczas kolejnych uruchomień crona. Aby wyczyścić ręcznie, wykonaj:

field_purge_batch(1);
Clive
źródło
1
Podczas dzwonienia field_delete_field()i field_purge_batch()pracy zapisuje w field_config_instancei field_config. Dlaczego?
berkes
Nie bardzo rozumiem, dlaczego wywołanie field_purge_batch o wartości 1 pozbywa się wszystkich danych pola. Jeśli dobrze rozumiem kod, pobiera on dane pola dla encji $ batchsize i pozostawia go przy tym (tj. Brak rekurencyjnego wywoływania funkcji lub czegokolwiek); wydaje się, że to do dzwoniącego należy sprawdzenie, czy wszystkie dane zniknęły, a jeśli nie, kontynuuj wywoływanie funkcji. Ale może coś zasadniczo nie rozumiem.
Eelke Blok,
Właściwie ten komentarz w field_ui.admin.inc wyjaśnia wiele: // Pola są czyszczone na cronie. Jednak moduł polowy zapobiega wyłączaniu modułów //, gdy dostarczone przez nich typy pól są używane w polu, dopóki nie zostanie całkowicie // wyczyszczone. W przypadku, gdy pole ma minimalną zawartość lub nie ma jej wcale, pojedyncze wywołanie // do field_purge_batch () usunie ją z systemu. Wywołaj to z // niskim limitem wsadowym, aby uniknąć konieczności oczekiwania administratorów na uruchomienie crona podczas // usuwania wystąpień spełniających te kryteria.
Eelke Blok
@Clive, ufam, że twoja rada jest niejawna, ale nie mogę się zorientować, jak dziwnie wydaje mi się mieć deklarację w warunku if. Czy to celowo? Mam na myśli $instance = field_info_instance('node', 'field_name', 'page'). Czy zamiast tego nie powinno być, $instance = field_info_instance('node', 'field_contact', 'job');a następnie upuścić instrukcję if?
cdmo
1
@ cdmo nazywa się to „przypisaniem w stanie” i tak, ma problemy . Ale rdzeń Drupala używa go swobodnie, nawet w najnowszej wersji, więc ma przynajmniej precedens. Szczerze mówiąc to było 5 lat temu i jestem teraz trochę mądrzejszy, albo go nie używam, albo jeśli z jakiegokolwiek powodu zamierzam to zrobić, kończę zadanie (np. if ( ($foo = $bar) ) {Więc intencja jest oczywista, a potencjał z powodu błędu jest ograniczony. Sama instrukcja if jest konieczna, ponieważ field_delete_instancenie sprawdza wartości null
Clive
5

Aby odpowiedzieć na pytanie @berkes:

field_delete_field()zaznacza pole do usunięcia, powodując jego oczyszczenie przy następnym uruchomieniu cron. Jednak to nie dane wyjeżdżać w field_config_instanceodniesieniu do pola spadły. Uruchomienie crona lub field_purge_batch()nie usunie tych danych z field_config_instancetabeli, nawet jeśli dla usuniętej kolumny ustawiono 1pole.

Dla mnie użycie, field_delete_instance()a następnie field_purge_batch()dla każdego wyczyszczonego pola zadziałało - natychmiastowe usunięcie zarówno pola z bazy danych (bez konieczności użycia crona), jak i czyszczenie field_config_instancetabeli dowolnych danych pola (dla usuniętego pola).

Oto rozwiązanie:

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

Zwróć uwagę na TRUEon field_delete_instance(), ponieważ oznacza to, że Field API powinien wykonywać operacje czyszczenia.

amator barista
źródło
Jak korzystać z tego kodu? Chcę usunąć pole tytułu z typu zawartości
Umair,