Как программно удалить поле из узла?

16

Как программно удалить поле из узла? У меня есть миграция, hook_update_Nкоторая перемещает содержимое из поля в пользовательскую таблицу. После этой миграции я хочу удалить поле в той же функции.

Есть ли какие-либо API полей, которые обслуживают удаление полей?

Редактирование, решение : поскольку в ответах отсутствует фактический код, я сделал это, чтобы переместить поля из $ users в мои собственные записи и впоследствии удалить это поле из базы данных;

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.
}
Беркеш
источник

Ответы:

29

field_delete_field($field_name)пометит $field_nameдля удаления при следующем запуске cron.

Вы можете использовать field_purge_batchдля удаления, если вы не хотите делать это при запуске cron.

РЕДАКТИРОВАТЬ: field_delete_field() следует использовать, когда вам нужно удалить поле из других пакетов. Если вы хотите удалить только поле из определенного пакета, вы должны использовать, field_delete_instance()как указано @Clive.

AjitS
источник
4
Тщательное, что также приведет к удалению поля из других пучков может быть прикрепленными к :) Полезно знать о field_purge_batchхотя
Clive
@Clive: верно, он удалит поле из всех пакетов. Спасибо за исправление :) Я отредактировал ответ.
AjitS
Я действительно хотел удалить поле целиком, то есть из всех связок. Но предупреждение это хорошо. Благодарю.
Беркес
1
field_delete_instance () это путь.
Райан МакВей
field_purge_batch () на самом деле удалит только столько элементов поля, сколько ему передан размер пакета. Это может помочь, когда в поле всего несколько элементов, поэтому, чтобы полностью избавиться от экземпляра поля, вам не нужно ждать, пока cron очистит его. Если у вас есть много значений в поле, не поддавайтесь искушению увеличить слишком большой размер пакета («партия» в названии не означает, что она будет выполнять какие-либо операции сама по себе, она просто означает, что она выполняет одну операцию) столько вещей, сколько вы попросите); Вы можете столкнуться с PHP-памятью или ограничениями по времени.
Элк Блок
24

Чтобы удалить поле из определенного пакета, вы можете использовать field_delete_instance()

Отмечает экземпляр поля и его данные для удаления.

Пример:

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

Чтобы полностью удалить поле из системы, вы можете использовать field_delete_field()

Отмечает поле, его экземпляры и данные для удаления.

Пример:

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

Поля / экземпляры помечаются только для удаления, данные будут фактически очищены во время последующих запусков cron. Для очистки вручную выполните:

field_purge_batch(1);
Клайв
источник
1
Во время звонка field_delete_field()и field_purge_batch()работы хранит записи в field_config_instanceи field_config. Это почему?
Беркес
Я не совсем понимаю, почему вызов field_purge_batch со значением 1 избавит от всех данных поля. Если я правильно понимаю код, он получает данные поля для сущностей $ batchsize и оставляет их при этом (то есть без рекурсивного вызова функции или чего-либо еще); Казалось бы, вызывающий должен проверить, все ли данные пропали, и если нет, продолжать вызывать функцию. Но, может быть, я что-то в корне неправильно понимаю.
Элк Блок
На самом деле, этот комментарий в field_ui.admin.inc объясняет это следующим образом: // Поля очищаются от cron. Однако модуль поля предотвращает отключение модулей //, когда предоставленные ими типы полей используются в поле до тех пор, пока оно // не будет полностью очищено. В случае, если у поля минимальное содержание или его нет, один вызов // field_purge_batch () удалит его из системы. Вызывайте это с // низким пределом пакета, чтобы избежать необходимости администраторов ждать запуска cron при // удалении экземпляров, которые соответствуют этому критерию.
Элк Блок
@Clive, я надеюсь, что вы в значительной степени неявно советуете, но я не могу понять, как странно выглядит объявление в условии if. Это специально? Я имею в виду $instance = field_info_instance('node', 'field_name', 'page'). Разве это не должно быть, $instance = field_info_instance('node', 'field_contact', 'job');а затем отбросить оператор if?
cdmo
1
@cdmo это называется «назначение в условии», и да, у него есть проблемы . Но ядро ​​Drupal использует его свободно, даже в последней версии, так что, по крайней мере, оно имеет прецедент. Честно говоря, это было 5 лет назад, и теперь я немного мудрее, либо я им не пользуюсь, либо, если по какой-то причине я собираюсь, я обертываю задание (например, if ( ($foo = $bar) ) {чтобы намерение было очевидным и потенциальным для ошибки ограничено. Сам оператор if необходим, потому field_delete_instanceчто не проверяет на
Clive
5

Чтобы ответить на вопрос @berkes:

field_delete_field()помечает поле для удаления, в результате чего оно очищается при следующем запуске cron. Однако он оставляет данные field_config_instanceо пропущенном поле. Запустив cron или field_purge_batch()не удалит эти данные из field_config_instanceтаблицы, даже если для удаленного столбца установлено значение 1для поля.

Для меня использование с field_delete_instance()последующим a field_purge_batch()для каждого очищенного поля сработало - мгновенное удаление как поля из базы данных (не требуя cron), так и очистка field_config_instanceтаблицы от любых данных поля (для удаленного поля).

Вот решение:

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

Обратите внимание на TRUEon field_delete_instance(), так как это означает, что Field API должен выполнять операции очистки.

любитель бариста
источник
Как использовать этот код? Я хочу удалить поле заголовка из типа контента
Umair