Bagaimana cara menghapus bidang dari suatu node secara terprogram?

16

Bagaimana cara menghapus bidang dari node secara terprogram? Saya memiliki migrasi hook_update_Nyang memindahkan konten dari bidang aa ke tabel kustom. Setelah migrasi itu, saya ingin menghapus bidang dalam fungsi yang sama.

Apakah ada API bidang yang melayani bidang penghapusan?

Sunting, Solusi : Karena jawaban tidak memiliki kode aktual, berikut adalah apa yang saya lakukan untuk memindahkan bidang dari $ users ke catatan saya sendiri dan kemudian menghapus bidang dari basis data;

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
sumber

Jawaban:

29

field_delete_field($field_name)akan menandai $field_namepenghapusan untuk cron run berikutnya.

Anda dapat menggunakan field_purge_batchuntuk melakukan penghapusan, jika Anda tidak ingin melakukannya pada cron run.

EDIT: field_delete_field() harus digunakan ketika Anda perlu menghapus bidang dari bundel lain juga. Jika Anda hanya ingin menghapus bidang dari bundel tertentu, Anda harus menggunakan field_delete_instance()sebagaimana disebutkan oleh @Clive.

Ajit
sumber
4
Hati-hati, itu juga akan menghapus bidang dari bundel lain yang mungkin melekat padanya :) Baik untuk mengetahui tentang field_purge_batchmeskipun
Clive
@Clive: benar, itu akan menghapus kolom formulir semua bundel. Terima kasih telah memperbaiki :) Saya sudah mengedit jawaban.
AjitS
Saya memang ingin menghapus bidang seluruhnya, yaitu dari semua bundel. Tapi peringatan itu bagus. Terima kasih.
berkelanjutan
1
field_delete_instance () adalah caranya.
Ryan McVeigh
field_purge_batch () sebenarnya hanya akan menghapus item bidang sebanyak jumlah batch yang diteruskan ke sana. Ini mungkin membantu ketika bidang hanya memiliki beberapa item, sehingga untuk benar-benar menyingkirkan contoh lapangan, Anda tidak perlu menunggu cron untuk membersihkannya. Jika Anda memiliki banyak nilai di bidang ini, jangan tergoda untuk menambah ukuran bets terlalu tinggi ("bets" dalam nama tidak berarti ia akan melakukan batching itu sendiri, itu hanya berarti ia melakukan batch tunggal sebanyak item yang Anda minta); Anda mungkin berakhir dengan kehabisan memori PHP atau batas waktu.
Eelke Blok
24

Untuk menghapus bidang dari bundel tertentu yang dapat Anda gunakan field_delete_instance()

Menandai instance bidang dan datanya untuk dihapus.

Contoh:

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

Untuk menghapus bidang dari sistem sepenuhnya, Anda dapat menggunakan field_delete_field()

Menandai bidang dan instans serta datanya untuk dihapus.

Contoh:

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

Field / instance hanya ditandai untuk dihapus, data akan benar-benar dibersihkan selama cron run berikutnya. Untuk membersihkannya jalankan secara manual:

field_purge_batch(1);
Clive
sumber
1
Saat menelepon field_delete_field()dan field_purge_batch()bekerja, ia menyimpan catatan di field_config_instancedan field_config. Mengapa demikian?
berkelanjutan
Saya tidak mengerti mengapa memanggil field_purge_batch dengan nilai 1 akan menghilangkan semua data lapangan. Jika saya mengerti kodenya dengan benar, ia mendapatkan data lapangan untuk $ batchsize entity dan membiarkannya demikian (yaitu tidak ada pemanggilan fungsi secara rekursif, atau apa pun); tampaknya terserah penelepon untuk memeriksa apakah semua data hilang dan jika tidak, terus memanggil fungsi. Tapi mungkin aku secara mendasar salah paham tentang sesuatu.
Eelke Blok
Sebenarnya, komentar di field_ui.admin.inc ini menjelaskan banyak hal: // Fields dibersihkan di cron. Namun modul bidang mencegah penonaktifan modul // ketika tipe bidang yang disediakannya digunakan dalam bidang sampai modul tersebut // sepenuhnya dihapus. Jika suatu bidang memiliki konten minimal atau tidak ada, panggilan tunggal // ke field_purge_batch () akan menghapusnya dari sistem. Sebut ini dengan // batas batch rendah untuk menghindari administrator harus menunggu cron berjalan ketika // menghapus instance yang memenuhi kriteria ini.
Eelke Blok
@Clive, saya percaya saran Anda cukup banyak secara implisit, tapi saya tidak bisa melupakan betapa anehnya bagi saya untuk memiliki deklarasi dalam kondisi if. Apakah itu disengaja? Saya mengacu $instance = field_info_instance('node', 'field_name', 'page'). Bukankah seharusnya sebaliknya $instance = field_info_instance('node', 'field_contact', 'job');dan kemudian menjatuhkan pernyataan if?
cdmo
1
@cdmo itu disebut "penugasan dalam kondisi", dan ya itu memang memiliki masalah . Tetapi inti Drupal menggunakannya secara bebas, bahkan dalam versi terbaru, jadi setidaknya sudah ada preseden. Sejujurnya ini 5 tahun yang lalu dan saya sedikit lebih bijaksana sekarang, saya tidak menggunakannya, atau jika untuk alasan apa pun saya akan, saya menyelesaikan tugas (mis. if ( ($foo = $bar) ) {Jadi niatnya jelas dan potensi untuk kesalahan terbatas Pernyataan if itu sendiri diperlukan karena field_delete_instancetidak memeriksa null
Clive
5

Untuk menjawab pertanyaan @berkes:

field_delete_field()tidak menandai bidang untuk dihapus, menyebabkannya dibersihkan pada cron run berikutnya. Namun itu tidak meninggalkan data field_config_instancetentang bidang yang dijatuhkan. Menjalankan cron atau field_purge_batch()tidak akan menghapus data ini dari field_config_instancetabel, bahkan jika kolom yang dihapus diatur ke1 untuk bidang tersebut.

Bagi saya menggunakan field_delete_instance()diikuti oleh field_purge_batch()untuk setiap bidang dibersihkan bekerja - langsung menghapus kedua bidang dari basis data (tanpa memerlukan cron), serta membersihkanfield_config_instance tabel data bidang apa pun (untuk bidang yang dihapus).

Ini solusinya:

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

Perhatikan TRUEpada field_delete_instance(), karena menunjukkan bahwa API Lapangan harus melakukan operasi pembersihan.

barista amatir
sumber
Bagaimana cara menggunakan kode ini? Saya ingin menghapus bidang judul dari jenis konten
Umair