7.x field.attach.inc field_attach_update($entity_type, $entity)

Save field data for an existing entity.

When calling this function outside an entity save operation be sure to clear caches for the entity:

entity_get_controller($entity_type)->resetCache(array($entity_id))

Parameters

$entity_type: The type of $entity; e.g. 'node' or 'user'.

$entity: The entity with fields to save.

Related topics

13 calls to field_attach_update()
comment_save in modules/comment/comment.module
Accepts a submission of new or changed comment content.
EntityFieldQueryTestCase::setUp in modules/simpletest/tests/entity_query.test
Sets up a Drupal site for running functional and integration tests.
EntityFieldQueryTestCase::testEntityFieldQueryMetaConditions in modules/simpletest/tests/entity_query.test
Tests field meta conditions.
EntityFieldQueryTestCase::testEntityFieldQueryTranslatable in modules/simpletest/tests/entity_query.test
Tests querying translatable fields.
FieldAttachOtherTestCase::testFieldAttachCache in modules/field/tests/field.test
Test field cache.

... See full list

File

modules/field/field.attach.inc, line 990
Field attach API, allowing entities (nodes, users, ...) to be 'fieldable'.

Code

function field_attach_update($entity_type, $entity) {
  _field_invoke('update', $entity_type, $entity);

  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);

  // Let any module update field data before the storage engine, accumulating
  // saved fields along the way.
  $skip_fields = array();
  foreach (module_implements('field_storage_pre_update') as $module) {
    $function = $module . '_field_storage_pre_update';
    $function($entity_type, $entity, $skip_fields);
  }

  // Collect the storage backends used by the remaining fields in the entities.
  $storages = array();
  foreach (field_info_instances($entity_type, $bundle) as $instance) {
    $field = field_info_field_by_id($instance['field_id']);
    $field_id = $field['id'];
    $field_name = $field['field_name'];
    // Leave the field untouched if $entity comes with no $field_name property,
    // but empty the field if it comes as a NULL value or an empty array.
    // Function property_exists() is slower, so we catch the more frequent
    // cases where it's an empty array with the faster isset().
    if (isset($entity->$field_name) || property_exists($entity, $field_name)) {
      // Collect the storage backend if the field has not been written yet.
      if (!isset($skip_fields[$field_id])) {
        $storages[$field['storage']['type']][$field_id] = $field_id;
      }
    }
  }

  // Field storage backends save any remaining unsaved fields.
  foreach ($storages as $storage => $fields) {
    $storage_info = field_info_storage_types($storage);
    module_invoke($storage_info['module'], 'field_storage_write', $entity_type, $entity, FIELD_STORAGE_UPDATE, $fields);
  }

  // Let other modules act on updating the entity.
  module_invoke_all('field_attach_update', $entity_type, $entity);

  $entity_info = entity_get_info($entity_type);
  if ($entity_info['field cache']) {
    cache_clear_all("field:$entity_type:$id", 'cache_field');
  }
}

Comments

manimejia’s picture

This documentation generating tool does not catch when functions are called from a $function_name() variable. Such is the case with node_save(), when it calls either field_attach_insert() or field_attach_update().

shrimphead’s picture

A great post about how to use this in updating a field but not the node...

http://blog.urbaninsight.com/2011/10/24/saving-nodes-fields-without-savi...
by Ki Kim

pabloroberto27’s picture

schlicki’s picture

Hey!

I have a module that sometimes loads and saves many nodes in one step. This can really get ugly when a user has to wait 10seconds to continue. It looks like the more fields the nodes have, the longer it takes to process them (sounds logical to me ;)).

Basically I do the followong:
- node_load
- change field value
- node_save

Would field_attach_update solve performance issues?

Thanks,
j

schlicki’s picture

I forget to mention that I would use the method of saving single fields only as posted by shrimphead ;)

gaborpeter’s picture

For me this setup worked:

$node = new stdClass();
$node->nid = $val;
$node->type = 'NODETYPE;
$node-field_whatever[LANGUAGE_NONE][0]['value'] = 'VALUE';
field_attach_presave('node', $node);
field_attach_update('node', $node);

AlxVallejo’s picture

I'm wondering if this is the performant way to update a node's fields. You're not using node_load so you're not creating an entire noad object from memory. Any insight?

Ashish.Dalvi’s picture

Correcting Minor typo in above exam.

$node = new stdClass();
$node->nid = $val;
$node->type = 'NODETYPE;
$node->field_whatever[LANGUAGE_NONE][0]['value'] = 'VALUE';
field_attach_presave('node', $node);
field_attach_update('node', $node);

efpapado’s picture

I think that

field_attach_presave('node', $node);
field_attach_update('node', $node);
entity_get_controller('node')->resetCache(array($node->nid));

should be avoided when the field you're trying to save is of type "taxonomy term reference" (as it is saved on field_config_instance.type table)

That's because, when you have a classic term reference field, every time you add a value, it is being saved in 2 tables: One is the (presumably) field_data_field_FIELDNAME, and the other is the taxonomy_index table.

It seems that using this function, only the first table gets updated. So, during full node view, you can see your new term value appearing in the field, but when you view the node into the /taxonomy/term/tid listing, the node doesn't show up.

I noticed it while working on a custom module. Then I discarder field_attach_update(), and I used node_save() which seems to work perfectly.

Could anyone test and confirm this?

Chaulky’s picture

I tried this approach and got the same results. This is because the taxonomy_index table in maintained in taxonomy_node_insert() and taxonomy_node_update(). Looks like this approach won't work for taxonomy references.

arpas’s picture

I analysed drupal core code and finished with

$node = node_load($id_value);
$node->field_field_name[LANGUAGE_NONE][0]['tid'] = 76;
field_attach_presave('node', $node);
field_attach_update('node', $node);
entity_get_controller('node')->resetCache(array($id_value));
taxonomy_node_update($node);

so taxonomy_index table was updated

kikecastillo’s picture

I think a call to db_transaction function before using this function is highly recommended or it is possible to have consistency problems or even content loss.
Read more information here: https://www.drupal.org/node/355875

polaki_viswanath’s picture

Hello,
I want to insert new field collection value to a node but without updating the associated node. Is there a way to do so, Since while saving any field collection value to a node the node itself is updated.

I have found this link (http://alexrayu.com/blog/saveupdate-field-collection-without-nodesave) but its not working in case of adding new field collection values to the node.

Any help would be much appreciated.

kikecastillo’s picture

Hello,

To update a field without updating the associated node you can do it this way:

$transaction = db_transaction();
try {
$node = node_load(1); // where 1 is the nid you want to change
$update_node = new stdClass();
$update_node->nid = $node->nid;
$update_node->vid = $node->vid;
$update_node->type = $node->type;
$update_node->field_FIELD_NAME['und'][0]['value'] = VALUE_YOU_WANT_TO_CHANGE;
field_attach_update('node', $update_node);
} catch (Exception $e) {
$transaction->rollback();
throw $e;
}

If you don't use db_transaction, you can lose content.

Best regards

scotself’s picture

Through trial and error, it seems the way to do this with users , you need uid and email or for some reason the user.token.inc file throws annoying notices in watchdog:

    $user = new StdClass();
    $user->uid = $uid;
    $user->mail = $mail;
    $user->my_custom_field[LANGUAGE_NONE][0]['value'] = $new_value;
    field_attach_update('user', $user);
tame4tex’s picture

One thing to be aware of when using field_attach_update() to update field values without saving the node, is that unless you specifically set $node->changed it will not get updated. $node-changed is used by node form to determine if current data is stale.

This means that if a user opens an edit node form prior to your field_attach_update() related function being called and then saves that node form after your field_attach_update() related function has run, if they both affected the same nid, any changes you make via field_attach_update() will be overwritten by stale data from the node form.