Comment supprimer par programmation un champ d'un nœud?

16

Comment supprimer un champ d'un nœud par programme? J'ai une migration hook_update_Nqui déplace le contenu d'un champ dans une table personnalisée. Après cette migration, je souhaite supprimer le champ dans cette même fonction.

Existe-t-il des API de champ qui permettent de supprimer des champs?

Modifier, Solution : Parce que les réponses manquent de code réel, voici ce que j'ai fait pour déplacer les champs des utilisateurs $ dans mes propres enregistrements et supprimer ensuite le champ de la base de données;

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
la source

Réponses:

29

field_delete_field($field_name)marquera la $field_namesuppression lors de la prochaine exécution cron.

Vous pouvez utiliser field_purge_batchpour effectuer la suppression, si vous ne voulez pas le faire sur cron run.

EDIT: field_delete_field() doit être utilisé lorsque vous devez également supprimer le champ d'autres ensembles. Si vous souhaitez uniquement supprimer le champ d'un ensemble particulier, vous devez utiliser field_delete_instance()comme mentionné par @Clive.

AjitS
la source
4
Attention, cela supprimera également le champ de tous les autres bundles auxquels il pourrait être attaché :) Bon à savoir field_purge_batchcependant
Clive
@Clive: à droite, il supprimera le champ de tous les bundles. Merci d'avoir corrigé :) J'ai édité la réponse.
AjitS
Je voulais supprimer le champ entièrement, c'est-à-dire de tous les paquets. Mais l'avertissement est bon. Merci.
berkes
1
field_delete_instance () est le chemin à parcourir.
Ryan McVeigh du
field_purge_batch () supprimera en fait seulement autant d'éléments de champ que la taille de lot qui lui est transmise. Cela peut être utile lorsque le champ ne contient que quelques éléments, de sorte que pour vous débarrasser complètement de l'instance de champ, vous n'avez pas besoin d'attendre que cron le nettoie. Si vous avez beaucoup de valeurs dans le champ, ne soyez pas tenté d'augmenter trop la taille du lot (le "lot" dans le nom ne signifie pas qu'il fera lui-même un lot, cela signifie simplement qu'il ne fait qu'un seul lot autant d’articles que vous le demandez); vous pourriez finir par courir dans la mémoire PHP ou les limites de temps.
Eelke Blok
24

Pour supprimer un champ d'un ensemble particulier, vous pouvez utiliser field_delete_instance()

Marque une instance de champ et ses données pour suppression.

Exemple:

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

Pour supprimer complètement un champ du système, vous pouvez utiliser field_delete_field()

Marque un champ et ses instances et données pour suppression.

Exemple:

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

Les champs / instances ne sont marqués que pour suppression, les données seront en fait purgées lors des cycles cron suivants. Pour le purger manuellement, exécutez:

field_purge_batch(1);
Clive
la source
1
Pendant les appels field_delete_field()et les field_purge_batch()travaux, il conserve les enregistrements dans field_config_instanceet field_config. Pourquoi donc?
berkes
Je ne comprends pas très bien pourquoi appeler field_purge_batch avec une valeur de 1 supprimera toutes les données de champ. Si je comprends bien le code, il obtient les données de champ pour les entités $ batchsize et les laisse à cela (c'est-à-dire sans appeler récursivement la fonction, ou quoi que ce soit); il semblerait qu'il appartient à l'appelant de vérifier si toutes les données ont disparu et sinon, continuer d'appeler la fonction. Mais peut-être que je comprends fondamentalement quelque chose.
Eelke Blok
En fait, ce commentaire dans field_ui.admin.inc explique en grande partie ceci: // Les champs sont purgés sur cron. Cependant, le module de champ empêche la désactivation des modules // lorsque les types de champ qu'ils ont fournis sont utilisés dans un champ jusqu'à ce qu'il soit // complètement purgé. Dans le cas où un champ a un contenu minimal ou nul, un seul appel // à field_purge_batch () le supprimera du système. Appelez ceci avec une // limite de lots faible pour éviter que les administrateurs n'aient à attendre les exécutions cron lors // de la suppression des instances qui répondent à ces critères.
Eelke Blok
@Clive, j'espère que vos conseils sont assez implicites, mais je ne peux pas oublier à quel point il me semble étrange d'avoir une déclaration dans une condition if. Est-ce exprès? Je fais allusion $instance = field_info_instance('node', 'field_name', 'page'). Ne devrait-il pas plutôt l'être $instance = field_info_instance('node', 'field_contact', 'job');, puis supprimer l'instruction if?
cdmo
1
@cdmo ça s'appelle "affectation en condition", et oui ça a des problèmes . Mais Drupal core l'utilise généreusement, même dans la dernière version, il a donc au moins un précédent. Pour être honnête, c'était il y a 5 ans et je suis un peu plus sage maintenant, soit je ne l'utilise pas, soit si pour quelque raison que ce soit, je termine la tâche (par exemple if ( ($foo = $bar) ) {, l'intention est évidente et le potentiel pour l'erreur est limitée. L'instruction if elle-même est nécessaire car field_delete_instancene vérifie pas null
Clive
5

Pour répondre à la question @berkes:

field_delete_field()marque le champ à supprimer, ce qui le purge lors de la prochaine exécution de cron. Cependant, il laisse des données sur field_config_instancele champ supprimé. L'exécution de cron ou field_purge_batch()ne supprimera pas ces données de la field_config_instancetable, même si la colonne supprimée est définie sur 1pour le champ.

Pour moi, utiliser field_delete_instance()suivi d'un field_purge_batch()pour chaque champ purgé travaillé - supprimer instantanément le champ de la base de données (sans nécessiter de cron), ainsi que purger la field_config_instancetable de toutes les données de champ (pour le champ supprimé).

Voici la solution:

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

Notez l' TRUEactivation field_delete_instance(), car cela indique que l'API de champ doit effectuer des opérations de nettoyage.

barista amateur
la source
Comment utiliser ce code? Je veux supprimer le champ de titre d'un type de contenu
Umair