Problem

Using field_attach_update() to update an entity's field values, without saving the entity, does not clear the entity's cache.

It's not uncommon for contrib modules to update field values by calling field_attach_update() directly. Posts such as this one suggest it as a good solution when you don't want to save the entity itself. Even the Pro Drupal 7 Development book suggests field_attach_update() as the way to update field information.

The Entity Translation module uses field_attach_update() when deleting field translations. Recently there was an issue reporting stale entity caches, and the solution was to use the entity controller's resetCache() method after calling field_attach_update().

Modules cannot reasonably be expected to always clear an entity's cache when using field_attach_update().

Solution

Implement hook_field_attach_update() to clear caches for the entity being updated via field_attach_update(). The other field_attach functions, such as field_attach_delete(), don't seem to be used often. However, it might make sense to implement hooks for those as well.

The downside is extra calls to cache_clear_all(), meaning extra db queries.

Alternative

If the maintainers are opposed to this, the Entity cache flusher module looks like a decent home for edge cases. That module should probably be mentioned on the project page.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

milesw’s picture

Status: Active » Needs review
FileSize
761 bytes

This patch implements hook_field_attach_update() to clear cache for an entity whenever field_attach_update() is called.

czigor’s picture

Status: Needs review » Reviewed & tested by the community

The patch works for me great, thanks!

An alternative to calling cache_clear_all() could be selectively removing the appropriate line from the cache table and recreate it. As far as I can see the cid is the id of the entity (at least for nodes) so it should be straightforward. I don't know how easy the recreation is.

czigor’s picture

Status: Reviewed & tested by the community » Needs work

I could work on the selective cache line replacement if someone reinforced me in this being the right way.

milesw’s picture

@czigor: Thanks for testing! Calling cache_clear_all() should already clear only the relevant rows from the cache table since we're passing an entity ID as the CID. And then entitycache will automatically save a new cache entry the next time an entity_load() happens for that entity. Hopefully that's the behavior you're getting. :)

czigor’s picture

Status: Needs work » Reviewed & tested by the community

You are right, I was confused by the name of the function and did not look close enough.

milesw’s picture

Status: Reviewed & tested by the community » Needs review

Would be nice to get some more reviews.

j0rd’s picture

I'll review this when I get a chance.

Additionally do we know if when we're saving a node, does this update hook get called for every single field in that node.

What I wouldn't want to see is repeated cache clears (if you're using a DB backend for the cache this could be bad) for each field in a node when performing a node_save().

If this is currently the case, we might want to queue up these clears via a drupal_static and make sure it only happens once. Unfortunately, this may be hard to determine.

Dave Reid’s picture

Status: Needs review » Postponed (maintainer needs more info)

In my opinion, if you are calling field_attach_update() manually rather than using an entity save (which I do actually use in the file_entity module), you should be responsible for calling entity_get_controller($entity_type)->resetCache(...) yourself.

milesw’s picture

Perhaps you can help push this documentation change through then? #2051787: Document that caches should be cleared after calling field_attach_update()