How can i determine whatever fields of "Field Collection" field were changed during saving of a node?
Inside my custom module i use hooks node_presave, node_update, node_insert but the problem is that inside this hooks i can load only new field values of "Filed Collection" field. After a little code research i have found out that inside field_collection_field_presave values are already saved to DB, so there is no way of getting previous ones... or is there?
PS: It is preferably to use node_$op hooks, but not form_alter or others, because in dependent from some of those fields i need to make another record to db.
Comments
Comment #1
Niremizov commentedAccording to the Field API "Only field modules that are storing or tracking information outside the standard field storage mechanism need to implement this hook." this applies to the hook_field_update and hook_field_insert. So probably save action's schould be made inside this 2 hooks but not inside hook_field_presave, like that for example:
Thus inside hook_node_presave we will have current values and strored values inside $node->original.
Comment #2
Niremizov commentedTill the save made inside field_collection_field_presave the only solution that i found is using hook_entity_presave($entity, $type).
Thus, to save previous values and use them inside hook_entity_update or hook_entity_insert you will need to use user function "your_module_function($previuos_value_of_field_collection)", for example:
After that you can receive previous values inside update hooks and make needed compare actions:
Comment #3
fagoI agree, we should do our save during insert/update, so feel free to roll a patch.
Still, comparing changes will be more difficult as usually I think, but at least you can load the original collections during presave then - yep.
Comment #4
geek-merlinin current dev
* fieldcollecitons are saved in field_collection_field_presave().
* old revisions are marked archived in field_collection_field_update() then.
according to "field_attach_insert":http://api.drupal.org/api/drupal/modules%21field%21field.attach.inc/func... hooks are:
* field_default_[op]()
* hook_field_[op]()
* hook_field_storage_pre_insert
* (storage)_field_storage_write
so looks like hook_field_storage_pre_insert() is a good point.
Comment #5
kscheirerBased on #1 and #3, attempted a patch - this is not my area of expertise, but I did my best to combine the proposed update hook in #1 with what was already in the module, and moved some presave code to the insert hook instead.
Comment #7
Niremizov commentedIn attached patch field_collection_field_presave was deleted and all its functionallity moved to hook_field_update and hook_field_insert.
Comment #8
Niremizov commentedComment #10
Niremizov commentedChanged variables naming and tested locally, should be ok now.
Comment #11
yannickooI would put the array in two lines like
Comment #12
Niremizov commentedComment #13
johnpitcairn commentedPatch at #12 applies cleanly and appears to work for me. It's very useful - it allows non Entity API aware modules like Workbench Moderation to set the default_revision status of the host entity before the field collection is saved.
Comment #14
johnpitcairn commentedHmm ... moving this logic to hook_field_update causes the Workbench Moderation problem at #1807460: Field collection doesn't play nice with workbench moderation (patch) to become worse - the first revision of the field collection will be the only revision you ever save?
Comment #15
johnpitcairn commentedIsn't this code at line 930 in field_collection_field_update() redundant? Won't any new entity already have passed through field_collection_field_insert() and have had its host entity set there?
For the code that follows that, it would be tremendously useful (in Drupal 7) if workflow modules could affect how entity revisions are dealt with. As it stands, the only way to do that is in hook_entity_presave(), but that has a couple of problems for modules like Workbench Moderation:
1 - field_collection_item_get_host_entity() returns a wrapped node, where the dynamic properties set by Workbench Moderation are not accessible.
2 - To save a draft revision, Workbench Moderation saves the node again in a shutdown function with $node->revision set to 0. This causes field_collection_field_update() to remove items, as noted in #1807460: Field collection doesn't play nice with workbench moderation (patch). But the patch proposed there adds workbench_moderation-specific code.
I propose the addition of an alter hook before $entity->save, and (maybe) some modification of the following item-removal logic. This would allow other modules to cleanly modify $entity, $host_entity and $original_by_id, and avoid the need to add workbench_moderation-specific checks to this module, or field_collection-specific logic to workbench_moderation. Further customization could be handled by a dedicated module - see Field Collection Workbench Moderation
Something like the attached (which also removes the redundant hostEntity check).
Comment #17
johnpitcairn commentedDuh. So maybe we do need the extra hostEntity check...
Comment #18
johnpitcairn commentedRe queueing ... OK then.
Comment #19
johnpitcairn commentedUnassigning kscheirer. Does anyone feel the proposed alter() hook should be a separate issue? It's a harmless addition because it requires explicit implementation to do anything. I think it's within the general spirit of the issue summary, but providing some additional flexibility beyond the reach of Entity API.
Comment #20
johnpitcairn commentedPatch at #17 won't do the job, because $item['entity'] isn't always present and therefore the alter hook will not always be called. This new patch is less far-reaching, and just provides the opportunity to alter how deletions are handled.
Modules wishing to intervene in hook_entity_presave() with host entity properties fully available can still do so by caching the host entity in an earlier hook.
Comment #21
johnpitcairn commentedCancel my request for a new hook, as per the comment by @hass. Reattaching the patch from @Niremizov at #12, marking RTBC.
Comment #22
fagoThanks, patch looks good. Committed.
Comment #23
yannickooFinally this was committed, thanks fago! :)
Comment #25
divined commentedget following error when try to save node after patching module:
where "field_data_field_metro" is a collection field with not required fields.
Comment #26
vladimirausThis patch breaks functionality for rules and tokens.
I created a rule where I'm trying to use values of multifield/multivalue field collection.
Example:
If I'll change field_collection_field_update back to field_collection_field_presave, the values are populated normally.
Otherwise they are just empty values.
Comment #27
vladimirausPatch to restore the generation of tokens as per comment 26
Comment #29
bmunslow commentedHi,
Perhaps I'm missing something, but I try to compare original FC values with new FC values in
hook_node_updateand I always get the new values, I can't see the old ones.$node->my_field_collectionmatches exactly$node->original->my_field_collectionI use
entity_metadata_wrapperto populate actual values of the field collection (instead fc ids).What would be the proper way to access original field_collection values?
EDIT:
Ok, for some reason I wasn't getting the updated results of the applied patch, even after clearing cache.
Long story short, the new values can be found in $node->my_field_collection, whereas $node->original->my_field_collection contains fc id which can be loaded to retrieve old values.
Comment #30
jmuzz commentedComment #31
milos.kroulik commentedPatch from #27 added tokens for me, but I encountered another issue:
This doesn't seem to be related to issue https://www.drupal.org/node/2186689 (which results in the same error), because I'm not deleting any field collection item in my rule.
I still have to try this on the clean site to be sure it's not environment-specific.
Comment #32
aaronelborg commentedNot sure if this is my exact issue or not so I apologize ahead of time if I'm barking up the wrong tree...
Basically, in hook_node_presave I'd like to compare node values that are about to be saved and depending on that, insert new FC values.
Thanks for any advice.
Comment #33
ilyasmdgh commented@AaronELBorg Even I wish to save field collection in hook_node_presave. Were you able to do that?? Thanks