¿Cómo eliminar mediante programación un campo de un nodo?

16

¿Cómo se elimina un campo de un nodo mediante programación? Tengo una migración hook_update_Nque mueve el contenido de un campo a una tabla personalizada. Después de esa migración, quiero eliminar el campo en esa misma función.

¿Hay alguna API de campo que atienda la eliminación de campos?

Editar, Solución : Debido a que las respuestas carecen de código real, esto es lo que hice para mover los campos de $ users a mis propios registros y, posteriormente, eliminar el campo de la base de datos;

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
fuente

Respuestas:

29

field_delete_field($field_name)marcará $field_namepara su eliminación en la próxima ejecución cron.

Puede usar field_purge_batchpara hacer la eliminación, si no desea hacerlo en la ejecución cron.

EDITAR: field_delete_field() debe usarse cuando necesite eliminar el campo de otros paquetes también. Si solo desea eliminar el campo de un paquete en particular, debe usarlo field_delete_instance()según lo mencionado por @Clive.

AjitS
fuente
44
Cuidado, eso también eliminará el campo de cualquier otro paquete al que se pueda adjuntar :) Sin field_purge_batchembargo
Clive
@Clive: a la derecha, eliminará el campo de todos los paquetes. Gracias por corregir :) He editado la respuesta.
AjitS
Quería eliminar el campo por completo, es decir, de todos los paquetes. Pero la advertencia es buena. Gracias.
Berkes
1
field_delete_instance () es el camino a seguir.
Ryan McVeigh
field_purge_batch () en realidad solo eliminará tantos elementos de campo como el tamaño de lote que se le pasa. Esto puede ayudar cuando el campo tiene solo unos pocos elementos, de modo que para deshacerse por completo de la instancia del campo, no necesita esperar a que cron lo limpie. Si tiene muchos valores en el campo, no tenga la tentación de aumentar el tamaño del lote demasiado alto (el "lote" en el nombre no significa que hará ningún lote en sí mismo, solo significa que hace un solo lote de tantos artículos como le pidas); puede terminar corriendo en la memoria PHP o los límites de tiempo.
Eelke Blok
24

Para eliminar un campo de un paquete particular, puede usar field_delete_instance()

Marca una instancia de campo y sus datos para su eliminación.

Ejemplo:

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

Para eliminar un campo del sistema por completo, puede usar field_delete_field()

Marca un campo y sus instancias y datos para su eliminación.

Ejemplo:

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

Los campos / instancias solo están marcados para su eliminación, los datos se eliminarán en las ejecuciones cron posteriores. Para purgarlo, ejecute manualmente:

field_purge_batch(1);
Clive
fuente
1
Mientras llama field_delete_field()y field_purge_batch()funciona, mantiene registros field_config_instancey field_config. ¿Porqué es eso?
Berkes
No entiendo por qué llamar a field_purge_batch con un valor de 1 eliminará todos los datos de campo. Si entiendo el código correctamente, obtiene los datos del campo para las entidades $ batchsize y lo deja así (es decir, sin llamar recursivamente a la función, ni nada); parecería que corresponde a la persona que llama verificar si todos los datos se han ido y, de lo contrario, seguir llamando a la función. Pero tal vez estoy malentendiendo algo fundamentalmente.
Eelke Blok
En realidad, este comentario en field_ui.admin.inc explica mucho esto: // Los campos se purgan en cron. Sin embargo, el módulo de campo evita la desactivación de los módulos // cuando los tipos de campo que proporcionaron se usan en un campo hasta que se // purga por completo. En el caso de que un campo tenga un contenido mínimo o nulo, una sola llamada // a field_purge_batch () lo eliminará del sistema. Llame a esto con un // límite de lote bajo para evitar que los administradores tengan que esperar las ejecuciones cron cuando // eliminen instancias que cumplan con este criterio.
Eelke Blok
@Clive, confío en que tu consejo está implícito, pero no puedo superar lo extraño que me parece tener una declaración en una condición if. ¿Eso es a propósito? Me refiero a $instance = field_info_instance('node', 'field_name', 'page'). ¿No debería ser así $instance = field_info_instance('node', 'field_contact', 'job');y luego descartar la instrucción if?
cdmo
1
@cdmo se llama "asignación en condición", y sí, tiene problemas . Pero Drupal core lo usa liberalmente, incluso en la última versión, por lo que tiene precedentes al menos. Para ser honesto, esto fue hace 5 años y ahora soy un poco más sabio, o no lo uso, o si por alguna razón voy a terminar la tarea (por ejemplo, if ( ($foo = $bar) ) {la intención es obvia y el potencial el error es limitado. La declaración if en sí misma es necesaria porque field_delete_instanceno verifica nulo
Clive
5

Para responder a la pregunta de @berkes:

field_delete_field()marca el campo para su eliminación, lo que hace que se purgue en la próxima ejecución cron. Sin embargo, deja datos field_config_instancesobre el campo descartado. Ejecutar cron o field_purge_batch()no eliminará estos datos de la field_config_instancetabla, incluso si la columna eliminada está configurada 1para el campo.

Para mí, el uso field_delete_instance()seguido de un field_purge_batch()para cada campo purgado funcionó: eliminar instantáneamente tanto el campo de la base de datos (sin requerir cron), como también purgar la field_config_instancetabla de cualquier dato de campo (para el campo eliminado).

Aquí está la solución:

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

Tenga TRUEen cuenta el encendido field_delete_instance(), ya que indica que la API de campo debe realizar operaciones de limpieza.

barista aficionado
fuente
¿Cómo usar este código? Quiero eliminar el campo de título de un tipo de contenido
Umair