Sorry this is so last minute, only realised this after a quick chat in irc last night with chx and Damien. I'll try to summarize the issues:
http://drupal.org/project/mongodb is going to provide non-SQL field storage.
field_attach_query() doesn't let you do things like get a list of nodes ordered by creation date with a certain field value - you can't join between SQL and non-SQL. This is why we have the taxonomy_index and forum_index tables in core (since SQL-SQL joins aren't exactly fast either).
So, mongodb field storage is very likely to store the entire entity in mongodb, so that lists etc. can be done with mongodb nifty query syntax.
There's also a mongodb caching backend.
Any site wanting to store fields out of SQL is likely to also want to use http://drupal.org/project/entitycache - since that also reduces hits to SQL.
entitycache also stores the entire entity object in whatever caching backend is supplied.
To avoid double storage of the same information in mongodb (triple storage if you count the entity data in SQL), it would make sense for mongodb to depend on entity cache so that we only store the information once - then it could be got via cache_get(), field_attach_query(), custom queries, or a views backend from the same place.
However entitycache relies on special casing core entities and implementing their specific hooks to handle cache setting, clearing etc. That's not acceptable for a field storage backend which needs to be able to handle any field attached to any arbitrary entity.
field_attach_presave() runs way before other hooks have run, so you don't have the complete entity - it's therefore only suitable for dealing with field values, not the full entity as it should be loaded.
Therefore, non-SQL field storage backends and/or entity cache, need to be able to implement an entity level hook which has access to the full object on insert/update and need to be able to respond to delete.
Probably the easiest way to do this is to add entity_invoke($op, $entity_type, $entity); calls in the right places.
I'm about to upload a patch for update/insert. Delete is tricky for two reasons:
1. hook_user_cancel() is by no means an equivalent for other _delete() hooks
2. It looks like field_attach_delete() is extremely inconsistently applied - it's likely that would suffice (although being inconsistent) since deletion is a more straightforward operation than insert/update - you have an ID, you delete stuff. This probably needs its own issue :/
I'm posting this as a critical bug report, because if the above summary is correct, pluggable field storage isn't currently possible in HEAD with non-SQL backends which provide some kind of query syntax (i.e. anything no-SQL-like).
| Comment | File | Size | Author |
|---|---|---|---|
| #16 | missing_entity_hooks.patch | 7.21 KB | catch |
| #3 | missing_entity_hooks.patch | 7.25 KB | catch |
| #1 | missing_entity_hooks.patch | 7.25 KB | catch |
Comments
Comment #1
catchAnd the patch. Hook docs need example code, probably needs some tests, but see what people think otherwise.
Comment #3
catchYeah yeah.
Comment #4
catchSomewhat related: #552716: Impossible to join or order by on field tables without using Views - field_attach_query() has limited functionality by design, so we need to let non-SQL-but-still-able-to-do-clever-stuff backends work around this in the same way that #569224: Expose field storage details through field attach. allows SQL storage to do joins.
Comment #5
chx commentedWell, what could I say? Although we are past every possible API freeze point, this only adds new APIs, does not hurt anyone and is indeed badly necessary. Noone needs to change their akready ported modules and calling this a new feature would be quite the stretch.
Comment #6
pwolanin commentedSeems like for D8 these hooks need to be unified, but probably this is too late for D7, unless we can do it like:
Which would let us remove all the calls like
Comment #7
pwolanin commentedhmm, well that won't work right for user module - though for D8 we should consider actually whether the user module's module of passing the existing object + new values (e.g. form values) is actually a more sensible general API.
Comment #8
dave reidA +1000 times yes. This would make a more generalize pathauto even easier to write in D7.
Comment #9
moshe weitzman commentedLooks safe and useful to me.
Comment #10
jherencia commentedSubscribing...
Comment #11
sun.core commentedHm... do we really want to re-introduce an $op pattern after working hard on eliminating almost all of them throughout core?
Why not simply:
module_invoke_all('entity_insert', 'file', $file);
here and likewise for the other invocations?
Powered by Dreditor.
Comment #12
webchickI think this issue contains sufficient arguments for including these hooks, even though we're post-post-post-API freeze. :P~
However, I share sun's question at #11.
Comment #13
catchWe removed the $op pattern for hook implementations, so that they don't have huge switch statements (and etc.), however the field API retains the $op pattern to avoid code duplication in central router functions - see http://api.drupal.org/api/function/_field_invoke/7 for example.
For why it's not just a module_invoke_all() see #6 - I'm hoping for a smoother transition to D8, and the first step would be unifying hook invocations between all the different entities. It's also very convenient to be able to document the entity_invoke() function, where it should be called etc., whereas it's considerably harder to document module_invoke_all() littered around the place.
However that's not at all essential for this patch to be useful so happy to re-roll with module_invoke_all() if it's preferred - if someone can explain where the docs should live (or if they can just be removed?). Leaving at CNR for now.
Comment #14
moshe weitzman commentedcatch's reply is reasonable. no more bikeshed IMO.
Comment #15
webchickOk, thanks for the rationale. Can I get a quick re-roll? A hunk in taxonomy.module failed.
Comment #16
catchComment #17
moshe weitzman commentedall green
Comment #18
webchickOK, thanks. Committed to HEAD.