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.
Comment | File | Size | Author |
---|---|---|---|
#1 | entitycache-1966164-1-hook-field-attach-update.patch | 761 bytes | milesw |
Comments
Comment #1
milesw CreditAttribution: milesw commentedThis patch implements hook_field_attach_update() to clear cache for an entity whenever field_attach_update() is called.
Comment #2
czigor CreditAttribution: czigor commentedThe 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.
Comment #3
czigor CreditAttribution: czigor commentedI could work on the selective cache line replacement if someone reinforced me in this being the right way.
Comment #4
milesw CreditAttribution: milesw commented@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. :)
Comment #5
czigor CreditAttribution: czigor commentedYou are right, I was confused by the name of the function and did not look close enough.
Comment #6
milesw CreditAttribution: milesw commentedWould be nice to get some more reviews.
Comment #7
j0rd CreditAttribution: j0rd commentedI'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.
Comment #8
Dave ReidIn 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.Comment #9
milesw CreditAttribution: milesw commentedPerhaps you can help push this documentation change through then? #2051787: Document that caches should be cleared after calling field_attach_update()