Supprimer par programme une entrée d'un champ sur une entité

13

Quelle est la bonne façon de supprimer par programme une entrée de champ spécifique pour un champ à entrées multiples d'une entité spécifique? (ce sont des champs et des entités spécifiques, pas des types de champs ou des instances et des types d'entités)

Voici quelques possibilités que j'ai examinées et qui ne fonctionnent pas:

  • Chargement de l'entité avec entity_load(), définition de l'entrée de champ sur = null ou = array (), puis enregistrement avec field_attach_update(). C'est le plus proche que j'ai trouvé, mais il laisse une entrée de champ nul zombie dans la base de données qui apparaît comme une ligne vide sur les formulaires jusqu'à ce que le formulaire soit enregistré et hook_field_is_empty()puisse démarrer ( hook_field_is_empty()est configuré de telle sorte que = null ou = array () marquera comme vide).
  • Chargement de l'entité avec entity_load(), suppression de l'entrée de champ par clé, puis enregistrement avec field_attach_update(). Cela semble ne rien faire - il semble que Drupal interprète l'entrée comme n'étant pas là comme un signe pour ne pas la modifier. (étrangement, j'obtiens également parfois des délais d'expiration de temps de requête maximum en essayant cette approche)
  • field_attach_delete() - c'est beaucoup trop brutal: il tue tous les champs de l'entité
  • field_purge_data() - mieux, mais toujours trop brutal: il tue toutes les entrées du champ, pas les entrées spécifiques

Donc, pour clarifier, j'ai un code qui trouve (et charge) une entité qui a un champ qui a plusieurs entrées et trouve une entrée spécifique sur ce champ qui doit être supprimée. Je souhaite supprimer complètement cette entrée, sans toucher aucune autre entrée ni aucun autre champ de l'entité.

user56reinstatemonica8
la source

Réponses:

24

Si vous êtes en mesure de vous fier au module API d'entité, vous devriez pouvoir utiliser du code similaire au suivant:

// Load some entity.
$entity = entity_load_single($entity_type, $id);

// Remove the field value.
unset($entity->field_FIELD_NAME[LANGUAGE_NONE][$index]);

// Reset the array to zero-based sequential keys.
$entity->field_FIELD_NAME[LANGUAGE_NONE] = array_values($entity->field_FIELD_NAME[LANGUAGE_NONE]);

// Save the entity.
entity_save($entity_type, $entity);
Clive
la source
2
Ça a marché! Merci, mon problème de zombie a maintenant été éradiqué. Quelques notes qui pourraient faire gagner du temps aux autres: j'avais besoin de mettre à jour l'api d'entité en RC2; puisque j'utilisais un nom de champ dynamique, la ligne non définie avait besoin d'accolades comme non définie ($ entity -> {$ field_name} [LANGUAGE_NONE] [$ index]); et pour éviter un avertissement, j'avais besoin d'encapsuler les array_values ​​() dans if (! empty (...)) {}
user56reinstatemonica8
Cela fonctionne également si vous voulez simplement effacer tout le champ et évite la redoutable "violation de contrainte d'intégrité: 1048 La colonne 'field_duty_user_target_id' ne peut pas être nulle"
Darrell Duane
Merci beaucoup! essayé de changer la valeur du champ via node_load, mais cela n'a pas fonctionné. Donc, changer la valeur d'un champ d'entité comme celui-ci fonctionne définitivement!
Артем Ильин
1

J'avais besoin de le faire dans le cadre d'un nettoyage de migration Drupal8.

Après quelques expérimentations, j'ai trouvé que l'itération puis l'utilisation de unset () sur le delta pouvaient le tuer. Mon exemple consistait à supprimer une balise (par conséquent, je recherche «target_id», pas «value» comme vous le feriez souvent pour d'autres champs.

/**
 * Removes a term from a field.
 *
 * @return bool
 *   success
 */
private function removeTerm(\Drupal\node\NodeInterface $object, \Drupal\taxonomy\TermInterface $term, $field_name) {
  // Check if tag value exists already.
  // Remember they may be multiples.
  /** @var @var \Drupal\Core\Field\FieldItemList $field_values */
  $field_values = $object->get($field_name);
  foreach ($field_values as $delta => $field_value) {
    if ($field_value->getValue()['target_id'] == $term->id()) {
      unset($field_values[$delta]);
      return TRUE;
    }
  }
  return FALSE;
}

Et après, en cas de succès, alors $object->save();

dman
la source
0

Pour Drupal 8, pour supprimer un champ d'une entité:

$entity = Node::load($nid);
unset($entity->field_name);

Cela appellera la méthode magique __unset () de ContentEntityBase:

public function __unset($name) {
    // Unsetting a field means emptying it.
    if ($this->hasField($name)) {
        $this->get($name)->setValue([]);
    }
    // For non-field properties, unset the internal value.
    else {
        unset($this->values[$name]);
    }
}

N'oubliez pas que, pour conserver vos changements, vous devez appeler

$entity->save();

Après avoir effectué toutes vos modifications.

Miguel Guerreiro
la source
-1

C'est la meilleure façon:

> $user = user_load($user->uid); 
> $user_wrp = entity_metadata_wrapper('user', $user);
> $user_wrp->{'field_data_multiple'} = array();
Mike Nguyen
la source
-2

la méthode préférée actuelle emploierait l'entité_metadata_wrapper

$node_wrapped = entity_metadata_wrapper('node', node_load($nid));

unset($node_wrapped->$field_name[$index];

c'est le meilleur tutoriel sur l'EMW que j'ai vu http://deeson-online.co.uk/labs/programately-access-field-data-using-entitymetadatawrapper-drupal

dotist
la source
cela n'a pas fonctionné. Je l'ai même essayé sans succès; $ wrapper = entity_metadata_wrapper ('node', $ duty); unset ($ wrapper-> field_duty_user); $ wrapper-> save (); node_save ($ duty);
Darrell Duane
1
La bonne façon serait $ node_wrapped-> field_name-> set (""); puis $ wrapper-> save ()
chadpeppers