3

I need to implement a function that checks if there has been a change from the previous existing node. If yes, send the updated changes.

I understand that Drupal has revision system and through diff we can see the difference between two revisions.

I want similar to that, however as an API call or a logic which can facilitate getting the difference.

  • 1
    Could you clarify your question? "If yes, send the updated changes" Send to where? Have you tried something so far? Could you paste your code? – typologist Sep 15 '15 at 17:12
  • Tried something, but I am convinced that drupal does it better as it has a way to get difference across revisions. Tried looking for it but could not find the exact documentation on that. – Amit Sedai Sep 15 '15 at 18:45
1

Either look at:

To easily "see" if changes exist. Or look at Migrates module track_changes implementation and implement it in code between revisions. All track_changes does is hash the fields of a content type together to get a unique ID. Different revisions of a node with changes between the body field will of course hash to a different value. Be sure to exclude node fields such as NID, vid, updated_at and other fields that (may) chnage between revisions.

Sample hash code from class MigrateSource:

// When tracking changed data, We want to quietly skip (rather than
// "ignore") rows with changes. The caller needs to make that decision,
// so we need to provide them with the necessary information (before and
// after hashes).
if ($this->trackChanges) {
    $unhashed_row = clone ($row);
    // Remove all map data, otherwise we'll have a false positive on the
    // second import (attempt) on a row.
    foreach ($unhashed_row as $field => $data) {
      if (strpos($field, 'migrate_map_') === 0) {
        unset($unhashed_row->$field);
      }
    }
    $row->migrate_map_original_hash = isset($row->migrate_map_hash) ?
      $row->migrate_map_hash : '';
    $row->migrate_map_hash = $this->hash($unhashed_row);
  }
  else {
    $row->migrate_map_hash = '';
  }
0

Amit's answer is super helpful, thanks for that. But there is one major error:

$diff = array_diff($new_value, $old_value);

PHP's array_diff will only tell you about values that are in the first param that are not in the second param. So, if we are updating a node and we delete (instead of add) a new value i na field, array_diff will not notice this and the node will not be marked by this code as changed (assuming that is the only change).

Instead, that line should be changed to:

$diff = array_merge(array_diff($new_value, $old_value), array_diff($old_value, $new_value));

I tested this locally, successfully.

I picked up that array_merge tidbit from https://stackoverflow.com/questions/10077840/difference-between-two-arrays

I don't have enough rep to comment on the post, but I can edit it, subject to moderation, so I will do that.

0

I wanted to know if there were any changes whenever a node gets updated. If yes, trigger the mail. The solution below works well for me (It could be improved though). I didn't try to get the exact difference, which however can be found using field_get_items() api.

$entity_old = entity_metadata_wrapper('node', $node->original);
$entity_new = entity_metadata_wrapper('node', $node);
// Fields comprising of field names array, whose changes you want to ignore
$ignore_fields_list = ignore_fields_list();
if(!is_object($entity_old)) {
  return;
}

$data = field_info_instances('node' ,$entity_new->getBundle());
$fields_list = array_keys($data);
$diff_list =  array();
foreach ($fields_list as $key => $field_name ) {
// Ignore if field name belong to ignore list
if(in_array($field_name, $ignore_fields_list )) {
  continue;
}

$old_value = $entity_old->{$field_name}->raw();
$new_value = $entity_new->{$field_name}->raw();
// If both are empty - ignore
if(empty($old_value) && empty($new_value)) {
  continue;
}
 // If one of the value is not empty compared to the other
if( (empty($old_value) && !empty($new_value) ) || (empty($new_value) && !empty($old_value))){
  // You can use field_get_items() to get the changed value.
  $diff_list[$field_name] = $data[$field_name]['label'];
  continue;
}

if(!is_array($new_value) && $new_value != $old_value) {
  $diff_list[$field_name] = $data[$field_name]['label'];
  continue;
}

if(is_array($new_value) && is_array($old_value)) {
  $diff = array_merge(array_diff($new_value, $old_value), array_diff($old_value, $new_value));
  if(!empty($diff)) {
    $diff_list[$field_name] = $data[$field_name]['label'];
  }
}
}

return $diff_list;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.