Looks like Diff doesn't support fields which are wrapped into a field collection.
From what I get, it seems that a diff is applied on the field collection entity rather than the fields inside. So, it notices a change but cannot render what actually changed...

I'll try to look closer at the source.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Alan D.’s picture

It is only returning the FC id.

Changes that I will hopefully include are:

      $build = $field_collection->view($settings['view_mode']);
      $diff_items[$delta] = drupal_render($build);

      if (!empty($settings['raw_markdown'])) {
        $func = $settings['raw_markdown'];
        if (function_exists($func)) {
          $diff_items[$delta] = $func($diff_items[$delta]);
          // Markdown process introduces line endings. Strip trailing
          // whitespaces as this is only indicative of changes.
          $diff_items[$delta] = trim($diff_items[$delta], "\n \t");
        }
      }

Meaning that you can only show the ID, or the rendered FC with selectable view mode and markdown options.

Alan D.’s picture

Title: Support of field collection module » Diff support of field collection fields
Project: Diff » Field collection
Version: 7.x-2.0 » 7.x-1.x-dev
Category: support » feature
Status: Active » Needs review
FileSize
2.86 KB

This is a patch for the new Diff 7.x-3.x branch. This provides field support via Diffs internal callback via it's own implementation of hook_entity_diff().

It provides a view mode and markdown options for the field when it is rendered for the comparison engine.

Note: It does not attempt to implement hook_entity_diff() itself, which would provide diff functionality on the entity itself (I'm not sure what other than fields would be required by Field Collection itself....)

fago’s picture

Status: Needs review » Needs work

#2 works for me, but when used two markdown options appear in the field_collection field settings. There is one "markdown callback" added in by diff.module and the "Raw Diff markdown callback" added in by the patch, whereas only the latter seem to take effect. I don't know what's the point in the form is then though, maybe a bug in the diff module? We should sort this out though.

Note: The @file comments needs an update.

rocketeerbkw’s picture

I don't think the extra raw markdown setting is needed as Diff module provides a default markdown setting.

The current functionality of comparing complete field collection output works OK, it would be awesome if we could invoke the individual field diff functions though... I tried doing this and failed hard. Here's an updated patch that addresses #3 in the meantime.

mitchell’s picture

Issue tags: +Diff integration

Tagging.

3CWebDev’s picture

I need to have diff support for field collections also and found this thread, however I am not able to get it functioning. Can someone please explain to me how to get this to work? I tried added the patch from #2 into a module but the collection fields are still ignored by the diff comparisons.

federico.parra’s picture

Hi! I tried patch in #6 and found not difference to the usual display of diff when
it comes to compare field collection.

It is very user unfriendly! Isn't a way to get a more visually easy/understandable comparison?

Thanks,
Federico

Alan D.’s picture

Really, the only benefit of this patch is to provide the FC id. The default diff modules use of the view modes settings mimic the other options that the display settings provide.

Open for suggestions here, remembering that FC item is simply a reference to another entity. One possible solution would be to alter diff_entity_fields_diff() so that it could insert an internal diff of the referenced entity (i.e. Field collections, Term references, Entity References, Node References, ...). I have added an issue for that here: #1897196: Support recursive Diffs of fields within fieldable entity references - Field collection, Entity reference, ...

federico.parra’s picture

FileSize
445.83 KB

This is what Diff comparison looks like when comparing two revisions of a node where several Field Collection entities have been edited/added/removed:

screenshot

As you can see only a developer would make any sense of this view.

The Diff should show the different in content, there should be no HTML at all in the screen.
Only the difference in texts in text fields, difference in choices in multiple choices fields, etc.

Is this even in the roadmap?

In my use case I need necessarily to be able to display to my client all the changes (a kind of undo-history)
he has done in the past to the node, and the node is full of Field Collections some of which contain Field Collections
within them!

Ideas?

Best and thank you
Federico

Alan D.’s picture

No test environment, and fuzzy with the inner workings as it has been a couple of months since I last looked through the code, but go to admin/config/content/diff and select marked down as default would be a good start. If you enable the "Revision comparison" display mode on this content type, you can hide these from the standard diff comparisons. (Names and URL from latest dev version)

Then there are few paths to follow up.

1) To create a new formatter for the FC to show the bits you want. Probably difficult to create a global solution for this.
2) to find and modify the current formatters to remove the edit links when in the view mode "diff_standard". Least the HTML would be tidier.
3) to make some formatter settings to control the edit / delete links. Again, just makes the HTML output cleaner.

No running FC environment at the moment to check this, but 2 and 3 may already be options in the module. Or there could be an existing formatter that will render the output cleaner. Enabling Revision comparison display mode gives you some control at least :)

federico.parra’s picture

Thank you so much Alan!!

I will try these options and report back.

Thank you,
Federico

Renee S’s picture

Federico, any luck? Running into this and it's yucky :)

heddn’s picture

Issue summary: View changes
FileSize
16.85 KB

Here's a solution to try while we get a more permanent thing in place. It might even give us some ideas on how to resolve it more permanently.

Field Collection Diff

Implement hook_entity_diff_alter(). For each of the field collections, pass the #old and #new html through a function that cleans up the HTML a little. I haven't tested it with multi-valued fields in a collection, but it works for single values.

function example_diff_cleanup($field) {
  if (is_array($field)) {
    $subject = implode(PHP_EOL, $field);
  }
  else {
    $subject = $field;
  }
  $pattern = '%(<div class="field-item\s.+?">.+?)(</div>)%';
  $replacement = '$1 $2';
  $subject = trim(preg_replace('/\s+/', ' ', $subject));
  return preg_replace($pattern, $replacement, $subject);
}
sylwester’s picture

@heedn, would you mind explaining #13 in more details? How would you pass values in hook_entity_diff_alter?

heddn’s picture

function example_entity_diff_alter(&$entity_diffs, &$context) {
  $entity_diffs['field_example_field_collection']['#old'] = example_diff_cleanup($entity_diffs['field_example_field_collection']['#old']);
  $entity_diffs['field_example_field_collection']['#new'] = example_diff_cleanup($entity_diffs['field_example_field_collection']['#new']);
}

jorges’s picture

As this still remains unresolved, you might be interested in my workaround. I have a Field Collection field_test, every of the possibly unlimited items holding 2 text fields field_test_arguments and field_test_expected content. (But the solution allows more text fields.)

Key feature is the $template variable, where I define how the collection text fields shall be rendered. In this example, the get rendered as example_test_arguments → example_test_expected_content.

/**
 * Implements hook_entity_diff_alter().
 */
function MY_MODULE_entity_diff_alter(&$entity_diffs, $context) { 

  if ($context['entity_type'] = 'MY_ENTITY_TYPE') {
    if ($context['bundle'] = 'MY_BUNDLE') {

      $entity_diffs['field_test']['#old'] = join("\n", MY_MODULE_render_field_collection_revision(
        $context['old_entity']->field_test, 
        array('field_test_arguments','field_test_expected_content'),
        '[field_test_arguments] → [field_test_expected_content]'
      ));
      $entity_diffs['field_test']['#new'] = join("\n", MY_MODULE_render_field_collection_revision(
        $context['new_entity']->field_test, 
        array('field_test_arguments','field_test_expected_content'),
        '[field_test_arguments] → [field_test_expected_content]'
      ));
    }
  }

}

/**
 * Render a field collection revision.
 *   (as https://www.drupal.org/node/1595702 remains unsolved.)
 *
 * @param array $field_collection 
 *   The field collection to render.
 * @param array $field_collection_field_names 
 *   The fields within the field collection to render.
 * @param string $template 
 *   The template to render the fields. 
 *   Should contain placeholders like [field_name].
 *
 * @return array $rendered_items 
 *   The rendered items.
 */
function MY_MODULE_render_field_collection_revision($field_collection, $field_collection_field_names, $template) {

  $rendered_items = array();
  foreach ($field_collection[LANGUAGE_NONE] as $item) {
    $fcitem = field_collection_item_revision_load($item['revision_id']);

    // Do nothing if field collection item could not be loaded.
    if (empty($fcitem)) {
      continue; 
    }
    // Do nothing if field collection fields are empty.
    foreach($field_collection_field_names as $field_collection_field_name) {
      if (empty($fcitem->{$field_collection_field_name})) {
        continue 2;
      }
    }

    // Take template as the render item base.
    $render_item = $template;
    foreach($field_collection_field_names as $field_collection_field_name) {
      // Replace placeholder in template with field value.
      // (Assumes fields with only 1 value.)
      $render_item = str_replace(
        '['. $field_collection_field_name . ']', 
        $fcitem->{$field_collection_field_name}[LANGUAGE_NONE][0]['value'],
        $render_item
      );
    }
    $rendered_items[] = $render_item;
  }
  return $rendered_items;
}

manuel.adan’s picture

This is also needed in D8 version. Open a new issue for that?

Bhuvana_Indukuri’s picture

Can someone confirm if any of these approaches were tested and if there is a workaround to this issue.

Bhuvana_Indukuri’s picture

Thanks @Jorges !! #17 worked for me.

hanoii’s picture

I tried @heddn approach with a different cleanup function and it's somehow quick to make it work, however, only after doing that I noticed there's a markdown diff on the link, not sure how new that is, but it does work pretty good. And you can configure it so that it's the default state of the diff.

Amir Simantov’s picture

Hi, thanks jorges for #17 - it works for me.

One fix, though: In function X_render_field_collection_revision I have wrapped the foreach with a condition:
if (isset($field_collection[LANGUAGE_NONE]))
This is needed when a field is empty.

If anybody needs to support an inner field that is a reference entity, then instead of checking for

$fcitem->{$field_collection_field_name}[LANGUAGE_NONE][0]['value']

One should check for
$fcitem->{$field_collection_field_name}[LANGUAGE_NONE][0]['target_id']

I needed the title so my code inside the function to render the item is:

$replacing = '';
if (isset($fcitem->{$field_collection_field_name}[LANGUAGE_NONE][0]['value'])) {
	$replacing = $fcitem->{$field_collection_field_name}[LANGUAGE_NONE][0]['value'];
}
else{
	// Then in our case it must be nid
	$nid = $fcitem->{$field_collection_field_name}[LANGUAGE_NONE][0]['target_id'];
	$node = node_load($nid);
	$replacing = $node->title;
}

  $render_item = str_replace(
    '['. $field_collection_field_name . ']', 
    $replacing,
    $render_item
  );
}

This is not a nice code, but it works ;)

skorzh’s picture

Status: Needs work » Needs review
FileSize
3.43 KB
236.95 KB

Hi!
My patch provides diff support for Field collections.
Looking forward for feedback.
Field collection diff example

  • skorzh authored 14aa14f on 7.x-1.x
    Issue #1595702 by skorzh: Diff support of field collection fields
    
jmuzz’s picture

Status: Needs review » Fixed

Looks good. Thanks for the patch!

If there are any issues with the new diff support please create a new issue rather than reopen this one.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

Amir Simantov’s picture

Hi. I was wondering why it is not committed to dev... Thanks.

Alan D.’s picture

It's both committed and present in the download

https://cgit.drupalcode.org/field_collection/tree/field_collection.diff....
https://www.drupal.org/project/field_collection/releases/7.x-1.x-dev

Will only kick into life with Diff 7.x-3.x and after the caches are fully cleared (aka you did run update.php after updating? or drush cc or /admin/config/development/performance, or admin menu clear all caches, ...)

Amir Simantov’s picture

Hi Alan, thanks for the clarification. However, I did not see here, in this very issue, any commit... How can one know, then, that it was committed? It is the first time that I see something like this in drupal.org, that is, that a patch was committed and in the issue it is not said it was. Could you please explain this to me so I can know better for next time? Thanks again, Amir

NWOM’s picture

@Amir Simantov check comment #24.

Amir Simantov’s picture

Ho, "authored" is like "submitted" - did not know that. Thanks!