In the mission to backport D8's Edit module to D7, we need to perform some investigation to see if the same approach (using TempStore to store edits in between field edits) is possible in D7 or not.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers’s picture

Issue summary: View changes
Issue tags: +sprint
Wim Leers’s picture

What?

The patch that implemented this in D8 can be found at #1901100-48: Make Edit module work with TempStore, so revisions are not saved on all atomic field edits (that is the back-end part, the front-end part of it was done in #1678002: Edit should provide a usable entity-level toolbar for saving fields). D8's TempStore is inspired by/based on CTools' "object cache" in D7.

Fears

I was pretty sure that ctools_object_cache_(get|set|clear)() will work for us.

What I was less certain of, is whether we can make these D8 code blocks work in D7, which may very well only be possible thanks to the vast improvements to Entity API in D8:

Initialization
+    // Replace entity with tempstore copy if available and not resetting, init
+    // tempstore copy otherwise.
+    $tempstore_entity = $this->tempStoreFactory->get('edit')->get($entity->uuid());
+    if ($tempstore_entity && !(isset($_POST['reset']) && $_POST['reset'] === 'true')) {
+      $entity = $tempstore_entity;
+    }
+    else {
+      $this->tempStoreFactory->get('edit')->set($entity->uuid(), $entity);
+    }
Making $entity->save() save to TempStore instead of DB
  public function validateForm(array &$form, array &$form_state) {
    $entity = $this->buildEntity($form, $form_state);
    field_attach_form_validate($entity, $form, $form_state, array('field_name' =>  $form_state['field_name']));

    // Do validation on the changed field as well and assign the error to the
    // dummy form element we added for this. We don't know the name of this
    // field on the entity, so we need to find it and validate it ourselves.
    if ($changed_field_name = $this->getChangedFieldName($entity)) {
      $changed_field_errors = $entity->$changed_field_name->validate();
      if (count($changed_field_errors)) {
        form_set_error('changed_field', $changed_field_errors[0]->getMessage());
      }
    }
  }

  public function submitForm(array &$form, array &$form_state) {
    $form_state['entity'] = $this->buildEntity($form, $form_state);

    // Store entity in tempstore with its UUID as tempstore key.
    $this->tempStoreFactory->get('edit')->set($form_state['entity']->uuid(), $form_state['entity']);
  }
Committing from TempStore to DB
+  /**
+   * Saves an entity into the database, from TempStore.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity being edited.
+   */
+  public function entitySave(EntityInterface $entity) {
+    // Take the entity from tempstore and save in entity storage. fieldForm()
+    // ensures that the tempstore copy exists ahead.
+    $tempstore = $this->tempStoreFactory->get('edit');
+    $tempstore->get($entity->uuid())->save();
+    $tempstore->delete($entity->uuid());
+
+    // Return information about the entity that allows a front end application
+    // to identify it.
+    $output = array(
+      'entity_type' => $entity->entityType(),
+      'entity_id' => $entity->id()
+    );
+
+    // Respond to client that the entity was saved properly.
+    $response = new AjaxResponse();
+    $response->addCommand(new EntitySavedCommand($output));
+    return $response;
+  }

Experiment

So, to check whether this was a founded fear or not, I set out to build a small experiment, employing the same strategy that we used for #1901100 and #1678002: the former is for the back-end implementation, with a new endpoint to hit to let the end-user decide "I'm done making edits, now I want them to be saved", the latter is the front-end to make all that work nicely.

I'm happy to report that it was a success! See the attached patch and accompanying 60-second screencast that shows it in action.

This experiment proves that it is viable to backport the exact UI/UX we have in Drupal 8, which will allow us to decrease the maintenance effort significantly. It's still possible and actually even likely that the Drupal 7 backport will require additional work-arounds for dealing with "extra fields" like the node title, node author and node date. But I'm confident those hurdles will be surmountable.

webchick’s picture

This is GREAT news!!!! :D

Gábor Hojtsy’s picture

I agree the experiment proves it should definitely be possible. Yay!

Wim Leers’s picture

Assigned: Unassigned » Wim Leers
Status: Needs review » Fixed
Issue tags: -sprint
Parent issue: » #2111667: Backport Drupal 8's Edit module to Drupal 7

Status: Fixed » Closed (fixed)

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