When adding or editing a field collection item that belongs to a node via the 'Embedded' method (i.e. the links that appear on the node view page) - if that node is under a revision control system (such as in my case 'Workbench moderation') - the changes made via these links are immediately updated, bypassing any revisioning or publishing workflows.

When the field collections are edited via the node edit form - the revisioning is respected (with this patch: #1807460: Field collection doesn't play nice with workbench moderation (patch)).

Many thanks,
Olly

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

baronmunchowsen’s picture

Title: Embedded Actions don't respect Node Revisioning » 'In Content' add/edit actions don't respect Node Revisions
FileSize
47.97 KB

I'm updating with some more information.

1) Content type with a field collection field
2) Field collection field 'widget type' set to Embedded.
3) Add content using node/add form - creates first revision
4) Edit content using node/%/edit form - edit content title and field collection - check create a new revision - creates second revision
5) Look at node revisions - the revisions respect the changes to the field collections

--everything hunky-dory here--

6) NOW - edit the field collection field value from the node page (node/%) - see attached
7) Edit the field collection field value - save - the field collection field value has been updated BUT the node has not created a new revision.

The issue here is that this allows changes to be made to field collections that belong to nodes without respecting the rules that the node might be restricted by - for instance a module like workbench_moderation.

I can see that it could be very tricky to check and see what entity/bundle the field collection field belongs to and then see what steps need to be taken when saving that field. Perhaps it would be simpler to add a permission or option to turn 'off' the direct field collection edit paths:
field-collection///edit
field-collection//add/node/
when configuring the field - making the fields only editable via the node edit form (and therefore follow any revision control rules that node is under)...

Cheers,
Olly

webchuck’s picture

Any progress on this issue? It seems like if we can create revisions from the node form, we should be able to do it more generally for all entity updates. I am willing to chip in some development time toward this, but am not too familiar with Entity API. Any suggestions on how we would approach this update?

webchuck’s picture

Okay, here's what I've found...

In field_collection.pages.inc, the add/edit form calls this function:

function field_collection_item_form_submit($form, &$form_state) {
  $field_collection_item = field_collection_item_form_submit_build_field_collection($form, $form_state);
  $field_collection_item->save();

Now we compare that to what's being called on node save:

function field_collection_field_presave($host_entity_type, $host_entity, $field, $instance, $langcode, &$items) {
  foreach ($items as &$item) {
    if (isset($item['entity']) || !empty($host_entity->revision)) {
      if ($entity = field_collection_field_get_entity($item)) {
        if (!empty($entity->is_new)) {
          $entity->setHostEntity($host_entity_type, $host_entity, LANGUAGE_NONE, FALSE);
        }
        if (!empty($host_entity->revision)) {
          $entity->revision = TRUE;
          $is_default = entity_revision_is_default($host_entity_type, $host_entity);
          if (!isset($is_default) || $is_default) {
            $entity->default_revision = TRUE;
            $entity->archived = FALSE;
          }
        }
        $entity->save(TRUE);
        ...
      }
    }
  }
}

So I tried to copy some of this to the add/edit form. I added the following:

function field_collection_item_form_submit($form, &$form_state) {
  $field_collection_item = field_collection_item_form_submit_build_field_collection($form, $form_state);
  
  $field_collection_item->revision = TRUE;
  $field_collection_item->default_revision = TRUE;
  $field_collection_item->archived = FALSE;
  
  $field_collection_item->save();
    
  drupal_set_message(t('The changes have been saved.'));
  $form_state['redirect'] = $field_collection_item->path();
}

And this worked! Kinda... It did save the node and create a new revision for the field collection.

Unfortunately, I'm using the Revisioning module, which keeps different states of the node, and that's really throwing things off. If I have a node in a saved/draft state, and edit the node again, I lose the previous modifications. So while this approach kinda works, it's obviously not the "right way" to be doing this.

Any thoughts from those who are deeply entrenched with this module?

davidsickmiller’s picture

Issue summary: View changes
FileSize
1.09 KB

I've made a patch that modifies the submit function to check the host entity's options and, if revisions are enabled, signals the field collection item's save() function to create a new host entity revision. This will work for adds and edits.

I personally would like host entity revisions to also be created upon deletion of a field collection item. Unfortunately, this goes through the field_collection_item_delete_confirm_submit() function, not field_collection_item_form_submit(), and seems to be more complicated.

On a side note, the field collection item's save() function has a comment that says "If this is creating a new revision, also do so for the host entity." and the nearby code does a check for $this->is_new_revision. I think either that comment is wrong or else the code is supposed to check $this->is_new. If the latter, a new host entity would already be always created when a field collection item is added (except with explicitly skipped with $skip_host_save), regardless of the changes in my patch.