13

What's the proper way to programmatically delete one specific field entry for a multi-entry field from one specific entity? (that's specific fields and specific entities, not field types or instances and entity types)

Here's some possibilities I've looked into which don't work:

  • Loading the entity with entity_load(), setting the field entry to =null or =array(), then saving with field_attach_update(). It's the closest I've found but it leaves a zombie null field entry in the database which shows up as a blank row on forms until the form is saved and hook_field_is_empty() can kick in (hook_field_is_empty() is configured such that =null or =array() will flag as empty).
  • Loading the entity with entity_load(), unsetting the field entry by key, then saving with field_attach_update(). This seems to do nothing - it seems that Drupal interprets the entry not being there as a sign to not modify it. (strangely I also sometimes get maximum query time expiration timeouts when trying this approach)
  • field_attach_delete() - this is much too blunt: it kills all fields for the entity
  • field_purge_data() - better, but still too blunt: it kills all entries of the field, not specific entries

So to clarify, I've got code that finds (and loads) an entity which has a field that has multiple entries, and finds a specific entry on that field that needs to be removed. I want to remove that entry completely, without touching any other entries or any other fields on the entity.

24

If you're able to rely on the entity API module you should be able to use code similar to the following:

// 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);
  • 2
    This worked! Thanks, my zombie problem has now been erradicated. A few notes that might save others time: I needed to update entity api to RC2; since I was using a dynamic field name the unset line needed braces like unset($entity->{$field_name}[LANGUAGE_NONE][$index]); and to avoid a warning I needed to wrap the array_values() in if(!empty(...)){} – user56reinstatemonica8 May 22 '12 at 9:14
  • This also works if you just want to clear the entire field, and avoids the dreaded "Integrity constraint violation: 1048 Column 'field_duty_user_target_id' cannot be null" – Darrell Duane Apr 19 '14 at 23:05
  • Thanks a lot! tried to change field value through node_load, but it didn't work. So changing entity field value like this definitely works! – Артем Ильин Apr 4 '18 at 7:44
1

I needed to do this as part of a Drupal8 migration cleanup.

After some experimentation, I found that iterating and then using unset() on the delta could kill it. My example was removing a tag (hence I search for 'target_id', not 'value' as you often would for other fields.

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

And afterwards, if success, then $object->save();

0

For Drupal 8, to delete a field from an entity:

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

This will call the magic method __unset() from 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]);
    }
}

Don't forget that, to persist your changes, you need to call

$entity->save();

After you've done all your changes.

-1

This is better way:

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

the current preferred method would employ the entity_metadata_wrapper

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

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

this is the best tutorial on the EMW that i've seen http://deeson-online.co.uk/labs/programatically-access-field-data-using-entitymetadatawrapper-drupal

  • this didn't work. I even tried it like this with no luck; $wrapper = entity_metadata_wrapper('node',$duty); unset( $wrapper->field_duty_user); $wrapper->save(); node_save($duty); – Darrell Duane Apr 19 '14 at 22:54
  • 1
    The correct way would be $node_wrapped->field_name->set(""); then $wrapper->save() – chadpeppers Jun 25 '14 at 2:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.