I'm adding certain fields from a content type into a custom form using field_attach_form(). When the form is submitted I'm processing those fields by calling field_attach_form_validate() and field_attach_submit() from #validate and #submit callbacks.
At that point, I want to compare the post-submit, prepared node object to the original node and only bother to node_save() it if any of the fields have changed. Therefore, I begin by loading the original node using entity_load_unchanged()
.
Unfortunately, the field arrays in the original node object don't match the field arrays in the prepared node object which is waiting to be saved, even if no changes have been made to the fields, so a simple "$old_field == $new_field" comparison is impossible. For example, a simple text field appears like this in the original:
$old_node->field_text['und'][0] = array(
'value' => 'Test',
'format' => NULL,
'safe_value' => 'Test',
);
Whereas in the prepared node it appears like this.
$node->field_text['und'][0] = array(
'value' => 'Test',
);
You might think to just compare the 'value' key, but then you run into fields made up of other elements which don't have 'value' keys. For example, let's look at an address field where there is no 'value' key and there are keys in both the old and prepared nodes which don't have counterparts.
Old node
$old_node->field_address['und'][0] = array(
'country' => 'GB',
'administrative_area' => 'Test',
'sub_administrative_area' => NULL,
'locality' => 'Test',
'dependent_locality' => NULL,
'postal_code' => 'Test',
'thoroughfare' => 'Test',
'premise' => 'Test',
'sub_premise' => NULL,
'organisation_name' => 'Test',
'name_line' => 'Test',
'first_name' => NULL,
'last_name' => NULL,
'data' => NULL,
);
Prepared node
$node->field_address['und'][0] = array(
'element_key' => 'node|page|field_address|und|0',
'thoroughfare' => 'Test',
'premise' => 'Test',
'locality' => 'Test',
'administrative_area' => 'Test',
'postal_code' => 'Test',
'country' => 'GB',
'organisation_name' => 'Test',
'name_line' => 'Test',
);
For empty fields, there is yet another discrepancy.
Old node
$old_node->field_text = array();
Prepared node
$node->field_text = array(
'und' => array(),
);
Can I generically compare any field's old and new value to detect whether it has changed or not?
Is this just an impossibility?
_field_invoke()
or something related to prepare full field structure from "prepared" node, render both fields and simply compare these HTML strings. Just an idea.