Como remover programaticamente um campo de um nó?

16

Como se remove um campo de um nó programaticamente? Eu tenho uma migração hook_update_Nque move o conteúdo de um campo para uma tabela personalizada. Após essa migração, desejo remover o campo nessa mesma função.

Existem APIs de campo que servem para remover campos?

Editar, Solução : Como as respostas não possuem código real, eis o que fiz para mover os campos dos $ users para os meus próprios registros e, posteriormente, remover o campo do banco de dados;

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
fonte

Respostas:

29

field_delete_field($field_name)marcará a $field_nameexclusão for na próxima execução cron.

Você pode usar field_purge_batchpara fazer a exclusão, se não quiser fazê-lo na execução do cron.

EDIT: field_delete_field() deve ser usado quando você precisar excluir o campo de outros pacotes também. Se você deseja excluir apenas o campo de um pacote específico, use field_delete_instance()o mencionado por @Clive.

AjitS
fonte
4
Cuidado, que também irá remover o campo de quaisquer outros pacotes que podem ser ligados a :) É bom saber sobre field_purge_batchembora
Clive
@Clive: à direita, ele excluirá o campo de todos os pacotes. Obrigado por corrigir :) Editei a resposta.
AjitS
Eu queria remover o campo completamente, ou seja, de todos os pacotes. Mas o aviso é bom. Obrigado.
Berkes
11
field_delete_instance () é o caminho a percorrer.
Ryan McVeigh 25/09
field_purge_batch () na verdade excluirá apenas quantos itens de campo forem passados ​​para o tamanho do lote. Isso pode ajudar quando o campo possui apenas alguns itens, para que, para se livrar completamente da instância do campo, você não precise esperar pelo cron limpá-lo. Se você tiver muitos valores no campo, não fique tentado a aumentar o tamanho do lote muito alto (o "lote" no nome não significa que ele próprio fará um lote, apenas significa que ele faz um único lote de quantos itens você pedir); você pode acabar executando na memória ou nos limites de tempo do PHP.
Eelke Blok
24

Para remover um campo de um pacote específico, você pode usar field_delete_instance()

Marca uma instância de campo e seus dados para exclusão.

Exemplo:

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

Para remover completamente um campo do sistema, você pode usar field_delete_field()

Marca um campo e suas instâncias e dados para exclusão.

Exemplo:

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

Os campos / instâncias são marcados apenas para exclusão, os dados serão realmente eliminados durante as execuções cron subsequentes. Para removê-lo manualmente, execute:

field_purge_batch(1);
Clive
fonte
11
Enquanto chama field_delete_field()e field_purge_batch()trabalha, mantém registros em field_config_instancee field_config. Por que é que?
Berkes
Não entendo por que chamar field_purge_batch com o valor 1 se livrará de todos os dados do campo. Se eu entendo o código corretamente, ele obtém os dados do campo para entidades $ batchsize e o deixa assim (ou seja, sem chamar recursivamente a função ou algo assim); parece que cabe ao chamador verificar se todos os dados se foram e, se não, continuar chamando a função. Mas talvez eu esteja entendendo algo fundamentalmente errado.
Eelke Blok
Na verdade, esse comentário em field_ui.admin.inc explica bastante: // Os campos são eliminados no cron. No entanto, o módulo de campo impede a desativação dos módulos // quando os tipos de campo fornecidos são usados ​​em um campo até que seja // totalmente eliminado. No caso de um campo ter conteúdo mínimo ou inexistente, uma única chamada // para field_purge_batch () o removerá do sistema. Chame isso com um // limite de lote baixo para evitar que os administradores tenham que esperar pela execução do cron ao // remover as instâncias que atendem a esse critério.
Eelke Blok
@Clive, confio em seus conselhos de forma implícita, mas não consigo superar o quão estranho me parece ter uma declaração em uma condição if. Isso é de propósito? Estou me referindo $instance = field_info_instance('node', 'field_name', 'page'). Em vez disso, não deveria ser $instance = field_info_instance('node', 'field_contact', 'job');e depois soltar a instrução if?
Cdmo # 11/17
11
@cdmo é chamado de "atribuição em condição", e sim, ele tem problemas . Mas o núcleo do Drupal o usa generosamente, mesmo na versão mais recente, pelo menos tem precedentes. Para ser sincero, isso foi há 5 anos e agora estou um pouco mais sábio, ou não o uso ou, por qualquer motivo, encerro a tarefa (por exemplo, if ( ($foo = $bar) ) {para que a intenção seja óbvia e o potencial o erro é limitado A instrução if em si é necessária porque field_delete_instancenão verifica nulo
Clive
5

Para responder à pergunta @berkes:

field_delete_field()marca o campo para exclusão, fazendo com que seja eliminado na próxima execução do cron. No entanto , deixa dados field_config_instancesobre o campo eliminado. A execução do cron ou field_purge_batch()não removerá esses dados da field_config_instancetabela, mesmo se a coluna excluída estiver configurada como1 para o campo.

Para mim, usei field_delete_instance()seguido por um field_purge_batch()para cada campo eliminado funcionou - removendo instantaneamente o campo do banco de dados (sem a necessidade de cron), além de limpar ofield_config_instance tabela de qualquer dado do campo (para o campo excluído).

Aqui está a solução:

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

Observe o que está TRUEativado field_delete_instance(), pois indica que a API do campo deve executar operações de limpeza.

barista amador
fonte
Como usar esse código? Eu quero excluir campo de título a partir de um tipo de conteúdo
Umair