Problem/Motivation

Currently, nodes are the only entity that support revisions. While there is support for loading revisions in the generic entity storage controller, there is no support for saving/deleting revisionable entities nor a way to delete revisions

Proposed resolution

The provided patch refactors and generalizes the node specific revision code, extends the entity storage controller and entity interfaces with the necessary methods and adds a default implementation for it.

Remaining tasks

Patch needs review.

User interface changes

None.

API changes

- EntityStorageControllerInterface::deleteRevision($revision_id)
- EntityInterface::isNewRevision()
- EntityInterface::setNewRevision($value = TRUE)
- $entity->revision, which is currently used as the flag for writing a new revions is removed and can no longer be used, isNewRevision() should be used instead.

CommentFileSizeAuthor
#99 entity-revision-save-delete-1723892-99.patch393 bytesmitchell
#84 entity-revision-save-delete-1723892-83.patch38.28 KBPancho
#84 interdiff.txt22.73 KBPancho
#82 entity-revision-save-delete-1723892-82.patch34.28 KBPancho
#82 interdiff.txt22.73 KBPancho
#73 entity-revision-save-delete-1723892-72.patch40 KBBerdir
#68 entity-revision-save-delete-1723892-68.patch40.33 KBBerdir
#64 entity-revision-save-delete-1723892-64.patch40.24 KBBerdir
#64 entity-revision-save-delete-1723892-64-interdiff.txt12.77 KBBerdir
#56 entity-revision-save-delete-1723892-56.patch36.8 KBBerdir
#56 entity-revision-save-delete-1723892-56-interdiff.txt709 bytesBerdir
#54 entity-revision-save-delete-1723892-54.patch36.4 KBBerdir
#52 entity-revision-save-delete-1723892-52.patch35.78 KBBerdir
#52 entity-revision-save-delete-1723892-52-interdiff.txt759 bytesBerdir
#50 entity-revision-save-delete-1723892-50.patch35.04 KBBerdir
#50 entity-revision-save-delete-1723892-50-interdiff.txt635 bytesBerdir
#48 entity-revision-save-delete-1723892-48.patch35.04 KBBerdir
#46 entity-revision-save-delete-1723892-46.patch35.01 KBBerdir
#46 entity-revision-save-delete-1723892-46-interdiff.txt6.11 KBBerdir
#42 entity-revision-save-delete-1723892-42.patch32.38 KBdas-peter
#42 interdiff-39-42.txt14.11 KBdas-peter
#40 entity-revision-save-delete-1723892-39-interdiff.txt6.3 KBBerdir
#40 entity-revision-save-delete-1723892-39.patch32.11 KBBerdir
#37 entity-revision-save-delete-1723892-37.patch31.62 KBBerdir
#37 entity-revision-save-delete-1723892-37-interdiff.txt617 bytesBerdir
#35 entity-revision-save-delete-1723892-35.patch31.62 KBBerdir
#35 entity-revision-save-delete-1723892-35-interdiff.txt1.27 KBBerdir
#33 entity-revision-save-delete-1723892-33.patch30.91 KBBerdir
#28 entity-revision-save-delete-1723892-28.patch30.93 KBBerdir
#24 entity-revision-save-delete-1723892-24.patch33.26 KBBerdir
#24 entity-revision-save-delete-1723892-24-interdiff.txt875 bytesBerdir
#22 entity-revision-save-delete-1723892-22.patch33.11 KBBerdir
#22 entity-revision-save-delete-1723892-22-interdiff.txt2.3 KBBerdir
#20 entity-revision-save-delete-1723892-20.patch33.14 KBBerdir
#20 entity-revision-save-delete-1723892-20-interdiff.txt730 bytesBerdir
#18 entity-revision-save-delete-1723892-18.patch30.82 KBBerdir
#18 entity-revision-save-delete-1723892-18-interdiff.txt14.46 KBBerdir
#16 entity-revision-save-delete-1723892-16.patch22.52 KBBerdir
#16 entity-revision-save-delete-1723892-16-interdiff.txt2.43 KBBerdir
#13 entity-revision-save-delete-1723892-13.patch21.65 KBBerdir
#13 entity-revision-save-delete-1723892-12-interdiff.txt8.68 KBBerdir
#11 entity-revision-1723892-11.patch23.86 KBBerdir
#11 entity-revision-1723892-11-interdiff.txt4.85 KBBerdir
#9 entity-revision-save-delete-1723892-9.patch20.32 KBBerdir
#9 entity-revision-save-delete-1723892-9-interdiff.txt1.89 KBBerdir
#7 entity-revision-save-delete-1723892-7.patch19.19 KBBerdir
#7 entity-revision-save-delete-1723892-7-interdiff.txt5.99 KBBerdir
#5 entity-revision-save-delete-1723892-5.patch13.84 KBBerdir
#2 entity-revision-save-delete-1723892-1.patch13.86 KBBerdir
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Berdir’s picture

Issue tags: +Entity system, +revision

Adding tags

Berdir’s picture

Title: Add support for revisions to EntityStorageController::save() » Add support for revisions for entity save and delete operation
Status: Active » Needs review
FileSize
13.86 KB

Here is a first try, let's see what the tests have to say.

We're not really saving that much code (other than being able to remove a lot of duplicated code in the node storage controller), but this will for example help #1374030: Remove entity_extract_ids() now that we have proper classed entity objects as I can completely remove the controller there once this is in.

Berdir’s picture

Title: Add support for revisions for entity save and delete operation » Support for revisions for entity save and delete operations

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-1.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
13.84 KB

Forgot to remove the additional argument in the node storage controller.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-5.patch, failed testing.

Berdir’s picture

Fixed the node tests fails and removed TestEntityController.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-7.patch, failed testing.

Berdir’s picture

Fixed test_entity test failures.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-9.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
4.85 KB
23.86 KB

Ok. Added support for saving revisions with predefined keys, this also allows for more simplifications in EntityFieldQueryTest.

Let's see if this passes...

Status: Needs review » Needs work

The last submitted patch, entity-revision-1723892-11.patch, failed testing.

Berdir’s picture

Oh wow, the last patch was nonsense. It was too late to write code.

Here's a better approach that adds a test entity specific flag and re-adds the controller to revert the ftvid if that is set. I have not found a way to figure that out without any flags, the previous patch broke re-saving/reverting old revisions. Not sure if that should be standardized.

I think we can remove the _old thing in favor of $entity->original->getRevisionId() but I left it there for now.

Interdiff is against #7.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-13.patch, failed testing.

klonos’s picture

Berdir’s picture

Ok, revamped the convertToPartialEntities(), with all those additional properties that need to be set now it's actually easier to use the from_ids() functions as well.

fago’s picture

Status: Needs review » Needs work
+++ b/core/modules/entity/lib/Drupal/entity/DatabaseStorageController.php
@@ -479,6 +493,42 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
+    $revision = clone $entity;

Having a clone here looks awkward. If the object is just for preparing the storage of the revision, it should be named like that and probably be a plain array of values ora stdclass object. E.g. $record or $storage_record?

+++ b/core/modules/entity/lib/Drupal/entity/DatabaseStorageController.php
@@ -479,6 +493,42 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
+    // ensure that a new revision will actually be created, then store the old
+    // revision ID in a separate property for use by hook implementations.
+    if ($revision->isNewRevision() && $revision->{$this->revisionKey}) {
+      $revision->{'old_' . $this->revisionKey} = $revision->getRevisionId();
+      $revision->{$this->revisionKey} = NULL;
+    }

I don't think we still need this old_revisionkey. For that $entity->original should work, shouldn't it? Or doesn't that contain the right revision? If so, I'd say that's what we want to fix: $original should be the previous version of whatever we are saving.

+++ b/core/modules/entity/lib/Drupal/entity/EntityInterface.php
@@ -46,6 +46,26 @@ interface EntityInterface {
+  /**
+   * Enforces an entity to be saved as a new revision.
+   *

Why is that enforcing something? Isn't it just setting the new revision flag? So maybe, it could be
just $entity->setNewRevision(); ?

+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -250,13 +97,42 @@ class NodeStorageController extends DatabaseStorageController {
+    if (!empty($node->revision)) {
+      $node->enforceNewRevision(TRUE);
+    }

I do think this should be part of the form code. If the revision checkbox is set, use the method. But I don't think we should still have $node->revision as the API is the method.

Berdir’s picture

Haven't touched the clone yet, not sure about what to do. We can do that, but then we need to pass $entity to prepareRevision() I think.

Renamed enforceNewRevision() to setNewRevision(), removed the $node->revision check from the storage controller, doing it outside now.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-18.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
730 bytes
33.14 KB

Fixed the weird empty( thing.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-20.patch, failed testing.

Berdir’s picture

Ok, the original change breaks the predefined test_entity revision id's, changed that pattern a bit. We do want to get rid of it in the long term I think but there are various tests that rely on it, especially the EFQ Tests.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-22.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
875 bytes
33.26 KB

Fixed the forum tests, they need a new way to figure out if a new revision was saved.

Status: Needs review » Needs work
Issue tags: -Entity system, -revision

The last submitted patch, entity-revision-save-delete-1723892-24.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
Issue tags: +Entity system, +revision
corvus_ch’s picture

Status: Needs review » Needs work
+++ b/core/modules/node/node.admin.incundefined
@@ -471,7 +471,6 @@ function node_admin_nodes() {
-    ->addTag('node_access')

Seems to me as an unintentional deletion.

Berdir’s picture

Status: Needs work » Needs review
FileSize
30.93 KB

Re-rolled my branch against 8.x, this should remove the accidental removal of that code.

Berdir’s picture

Status: Needs review » Needs work
Issue tags: +Entity system, +revision

The last submitted patch, entity-revision-save-delete-1723892-28.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
30.91 KB

Re-roll.

corvus_ch’s picture

Status: Needs review » Needs work
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.phpundefined
@@ -321,6 +321,11 @@ class NodeFormController extends EntityFormController {
+    // Save as a new revision if requested to do so.
+    if (!empty($node->revision)) {
+      $node->setNewRevision();

Use $form_state['values'] instead

/modules/file/file.field.inc file_field_update() still uses !empty($entity->revision) instead of $entity->isNewRevision().

Berdir’s picture

Fixed those two things.

Note that the first point about the clone $entity from #17 is still open. Not sure what to do about it, need to discuss it with fago.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-35.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
617 bytes
31.62 KB

Weird typo that netbeans did not recognize as a PHP syntax error.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-37.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review

Ok, here we go, fixed the test fails and changed $revision to a $record array.

Note that the change there is fragile and will break the issue that attempts to separate $original from $entity.

We discussed several things on how this could be fixed in the long-term:
- Pass original through that hook as well
- Remove hook_field_update() and similar in favor of hook_entity_update(), which would eliminates quite a few hooks.
- For this specific issue, we could add proper revision support to the file usage API, and actually register the revision id too. Right now, this is a problem anyway, because we have no clue what exactly happens when you have multiple revisions where some have a file and some don't. We have no idea what to do when we start deleting those revisions...

Berdir’s picture

das-peter’s picture

Assigned: Unassigned » das-peter
Status: Needs review » Needs work

Needs a re-roll, I'm working on that right now.

das-peter’s picture

Status: Needs work » Needs review
FileSize
14.11 KB
32.38 KB

Okay, here we go. I re-rolled the patch, let's see if it passes the tests.
I fixed some coding standard violations at the same time.

For now the only part I'm a bit concerned about is this:

...
    elseif (!isset($record['log']) || $record['log'] === '') {
      // If we are updating an existing node without adding a new revision, we
      // need to make sure $node->log is unset whenever it is empty. As long as
...

At first it looks like the condition could be adjusted to simply use empty(), even the comment below the condition implicitly says that. But according to Sascha, who I bothered with this, using empty() would lead to failing tests.
Shall we improve the comment or just hope that nobody has the idea to clean this up?

fago’s picture

Status: Needs review » Needs work

Patch does not apply any more :/

fago’s picture

Also, this does not cover deleting yet. Looks like this does not even use the controller yet:
http://api.drupal.org/api/drupal/core!modules!node!node.module/function/...

fago’s picture

I've worked on the entity api module's revision support today, patch over at http://drupal.org/node/996696#comment-6433746. This incorporates already #218755: Support revisions in different states as well as code of this patch - maybe it's useful for this patch as well.

Berdir’s picture

Ok, re-rolled and added deleteRevision(). Let's see if this passes.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-46.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
35.04 KB

Hm, 8.x is moving fast ;) New try.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-48.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
635 bytes
35.04 KB

isCurrentRevision is now protected.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-50.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
759 bytes
35.78 KB

Added a dummy implementation for deleteRevision() to the config storage controller.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-52.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
36.4 KB

Re-rolled after the current/default revision changes. Let's see if this will pass, hope that issue has added proper tests ;) Also fixed the TestEntitycontroller exceptions.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-54.patch, failed testing.

Berdir’s picture

Had to fix one of these new tests..

moshe weitzman’s picture

Please add a Summary. Thanks

das-peter’s picture

Assigned: das-peter » Unassigned
Berdir’s picture

Added an issue summary.

moshe weitzman’s picture

Status: Needs review » Needs work

If this is a new hook, it needs docs: $this->invokeHook('revision_delete', $revision);

// When saving a new revision, set any existing revision ID to NULL
This is not good for data migration between Drupal sites (e.g. D7 => D8). Can we think of a way to honor a revision_id if caller provided one? Nodes and Users currently let you specify a nid/uid so I'm hoping that we can do similar here. This is probably worthy of a follow-up, and shouldn't block this patch.

$entity->use_provided_revision_id. Looks like this is a new, magic key :). We should document it

typo: deleeted

Berdir’s picture

About the forceful revision ID override, agreed that this is not optimal but that's how it currently works in node.module. I tried to improve that, but it's quite complicated.

The only thing that I was able to come up with was an explicit flag that is currently only used by the test entity, which requires exactly this: fixed, predefined revision id's because they are then checked in test assertions. The implementation there is just a very ugly hack to get the tests working. We could easily standardize this with a method, but we already have quite a few of those methods and I'm not too fond of adding even more of them.

Ideas?

moshe weitzman’s picture

I just looked for the equivalent logic when saving nodes/users with specific IDs and it might have been removed in D8 (including the tests for it) which really sucks. Anyway, what D7 does is honor a specified id when an id is passed AND an is_new flag is set. I don't know if it makes sense to do that here. If it doesn't, your approach looks fine to me.

Berdir’s picture

Confirmed, this is the code snippet from 7.x:

  // When saving a new node revision, unset any existing $node->vid so as to
    // ensure that a new revision will actually be created, then store the old
    // revision ID in a separate property for use by node hook implementations.
    if (!$node->is_new && !empty($node->revision) && $node->vid) {
      $node->old_vid = $node->vid;
      unset($node->vid);
    }

And it looks like the check exists in 8.x as well:

+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.phpundefined
@@ -217,39 +86,6 @@ class NodeStorageController extends DatabaseStorageController {
-      // When saving a new node revision, unset any existing $node->vid so as to
-      // ensure that a new revision will actually be created, then store the old
-      // revision ID in a separate property for use by node hook implementations.
-      if (!$node->isNew() && !empty($node->revision) && $node->vid) {
-        $node->old_vid = $node->vid;
-        $node->vid = NULL;
+++ b/core/modules/entity/lib/Drupal/entity/DatabaseStorageController.phpundefined
@@ -498,6 +536,43 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
+    // When saving a new revision, set any existing revision ID to NULL so as to
+    // ensure that a new revision will actually be created, then store the old
+    // revision ID in a separate property for use by hook implementations.
+    if ($entity->isNewRevision() && $record[$this->revisionKey]) {
+      $record[$this->revisionKey] = NULL;

But here I somehow messed up up :) Comment is outdated as well. Probably needs a test for this. Will try to update this soon. Back from a 3 week absence, lots of things to catch up...

Berdir’s picture

Ok, here is the promised re-roll.

- Re-added the new entity check. The reason I removed it is that isNew() doesn't work in there, just like postSave(). Added the same workaround, a $update argument to saveRevision().
- Added documentation for hook_entity_revision_delete().
- The is new check actually made most of the usage of use_provided_revision_id unecessary, the only exception was the EntityFieldQuery tests that try to create new revisions with specific ids of an existing entity. I refactored that to use dynamic id's instead. This allowed me to remove that flag again and also the whole test entity controller class. Win!
- I'm unable to find the deleeted typo?

This means that we actually save code in the end, yay!:
22 files changed, 243 insertions(+), 284 deletions(-)

Let's see if this passed the tests.

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

Looks like all my concerns were addressed, and bot is happy.

Berdir’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Entity system, +revision

The last submitted patch, entity-revision-save-delete-1723892-64.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
40.33 KB

Re-rolled after the entity property api patch went in.

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

thx

Berdir’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Entity system, +revision

The last submitted patch, entity-revision-save-delete-1723892-68.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review

Re-roll.

Wondering if this isn't actually a task instead of a feature. Would be really nice to have this in so that #1498674: Refactor node properties to multilingual can build on this, instead of having to do the work twice.

Berdir’s picture

Erm. with patch.

xjm’s picture

I agree that this is more of a task, since we're generalizing existing functionality from one entity type to all entities. The diffstat illustrates this. :)

xjm’s picture

Category: feature » task
moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC. This sat at RTBC for a week. Lets please get it in soon.

plach’s picture

Issue tags: +Avoid commit conflicts
catch’s picture

I'm leaving this RTBC but it'd be good to understand the following (apart from the initial nitpick) a bit better since it's not explained well in the patch.

+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.phpundefined
@@ -507,6 +520,47 @@ public function save(EntityInterface $entity) {
+   * Saves a node revision.
+   *
+   * @param Drupal\entity\EntityInterface $node

s/entity/node/ ?

+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.phpundefined
@@ -507,6 +520,47 @@ public function save(EntityInterface $entity) {
+    // Convert the entity into a array as it might not have the same properties
+    // as the entity, it is just a raw structure.
+    $record = (array) $entity;

I don't understand this comment tbh. Why won't it have the same properties as the entity? If it's got a different structure to the Entity then what about an EntityRevisionInterface or similar.

+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.phpundefined
@@ -540,6 +594,16 @@ protected function preDelete($entities) { }
   /**
+   * Act on a revision before being saved.
+   *
+   * @param array $record
+   *   The revision array.
+   * @param Drupal\entity\EntityInterface $entity
+   *   The entity object.
+   */
+  protected function preSaveRevision(array &$record, EntityInterface $entity) { }

So we have the revision being passed as an array, and the entity being passed as an entity. Why would those be different at all? Also I have no idea what the structure of $record might be reading the documentation here.

+++ b/core/modules/node/lib/Drupal/node/NodeFormController.phpundefined
@@ -321,6 +321,11 @@ public function submit(array $form, array &$form_state) {
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php

diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index 02e694e..482d534 100644

index 02e694e..482d534 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php

--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.phpundefined

The diffstat on this file is amazing.

Berdir’s picture

Thanks for reviewing.

I've discussed the record thing in Munich with @fago. The reason for using an array there is that a revision usually has additional stuff on it that the entity doesn't. An interface doesn't help because this isn't about methods. We just need a data structure to be able to save it.

It is *similar*, although not equal the way the new DatabaseStorageControllerNG works. The entity object is converted to a dumb record in mapToStorageRecord(). The difference there is it is a class and it has only the properties defined that actually exist on the table. What about doing the same here, then we can document it as "has the properties of the revision table" ?

Not sure if we want to do that now or as a follow-up/while converting to the properties based structure.

Pancho’s picture

Did I miss the point, why the abstracted entity_revision_delete() - which was there in patch #56 - disappeared again, so node_revision_delete() and other entity types still need to do a "manual" db_delete()?
Otherwise a nice enabler!

Berdir’s picture

Status: Reviewed & tested by the community » Needs work

Looks like I re-rolled this on an old patch.

Pancho’s picture

Status: Needs work » Needs review
FileSize
22.73 KB
34.28 KB

Hmm, seems we need to take a few steps back.
Here's a straight re-roll of #56 against HEAD, with just a few obvious typos and glitches fixed.
Now we'd need to catch up with the changes since #56. Wasn't completely sure about what was on purpose and what was erroneous. Probably Berdir knows best.
The supplied interdiff is against #73.

Status: Needs review » Needs work

The last submitted patch, entity-revision-save-delete-1723892-82.patch, failed testing.

Pancho’s picture

Status: Needs work » Needs review
FileSize
22.73 KB
38.28 KB

Hmm, #82 applied cleanly here. Another try with some more minor doc fixes (+ stats)...
If the testbot can't apply, I don't know.
The supplied interdiff is still against #73.

fubhy’s picture

+++ b/core/includes/entity.incundefined
@@ -150,6 +150,18 @@ function entity_revision_load($entity_type, $revision_id) {
+ * Deletes a node revision.

Deletes an 'entity revision'

+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.phpundefined
@@ -243,6 +243,23 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
+      $this->invokeHook('revision_delete', $revision);

Let's change this to 'delete_revision'.

+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.phpundefined
@@ -548,7 +632,13 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
+    $function = 'field_attach_' . $hook;
+    // @todo: field_attach_delete_revision() is named the wrong way round,
+    // consider renaming it.
+    if ($function == 'field_attach_revision_delete') {
+      $function = 'field_attach_delete_revision';
+    }
+    if (!empty($this->entityInfo['fieldable']) && function_exists($function)) {

See comment above.

+++ b/core/lib/Drupal/Core/Entity/Entity.phpundefined
@@ -43,6 +43,13 @@ class Entity implements IteratorAggregate, EntityInterface {
   /**
+   * Boolean indicating whether a new revision should be created on save.
+   *
+   * @var bool

"Indicates whether this is a new revision."

+++ b/core/lib/Drupal/Core/Entity/EntityInterface.phpundefined
@@ -64,6 +64,26 @@
+   * Returns whether a new revision should be created on save.
+   *
+   * @return bool
+   *   TRUE if a new revision should be created.
+   *
+   * @see Drupal\Core\Entity\EntityInterface::setNewRevision()
+   */
+  public function isNewRevision();

That comment refers to what we are using it for, not what it actually does. What it does is, it returns whether an instance is a new revision of an entity.

+++ b/core/lib/Drupal/Core/Entity/EntityInterface.phpundefined
@@ -64,6 +64,26 @@
+  /**
+   * Enforces an entity to be saved as a new revision.
+   *
+   * @param bool $value
+   *   (optional) Whether a new revision should be saved.
+   *
+   * @see Drupal\Core\Entity\EntityInterface::isNewRevision()
+   */
+  public function setNewRevision($value = TRUE);

Same here basically.

fubhy’s picture

Status: Needs review » Needs work
Berdir’s picture

> Let's change this to 'delete_revision'.

Disagree. the function is called entity_revision_delete() (which is consistent with entity_revision_load()), so the hook should be hook_entity_revision_delete(). It's the field attach function that's named wrong, not the other way round :)

> That comment refers to what we are using it for, not what it actually does. What it does is, it returns whether an instance is a new revision of an entity.

Hm. I get your point, but not sure. This flag is only relevant between being set and save, and setting it usually happens immediately before saving it. What is "a new revision of an entity"? At this moment, it's just a (possibly) modified entity. There will only be a new revision with a new revision id after it has been saved, at which point this function will actually return FALSE. Maybe "Returns if the entity will be saved as a new revision"?

moshe weitzman’s picture

Still Needs Work?

fubhy’s picture

Status: Needs work » Reviewed & tested by the community

Ah whatever. I guess I was just nit picking. I can live with it the way it is :)

mitchell’s picture

webchick’s picture

Title: Support for revisions for entity save and delete operations » Change notice: Support for revisions for entity save and delete operations
Priority: Normal » Critical
Status: Reviewed & tested by the community » Active
Issue tags: +Needs change record

Just to clear up any misconceptions about #76, this sat for a week at RTBC because we were over thresholds during that time, and this was classified as a feature request. And we're currently over thresholds again. I agree with this issue's re-classification as a task, however, because as xjm mentions in #74, this is more refactoring than a new feature. And what a lovely refactoring indeed! :D

Committed and pushed to 8.x, along with a CHANGELOG.txt update. WOOHOO. This'll need a change notice.

jhodgdon’s picture

Issue tags: -Avoid commit conflicts

de-tagging

chx’s picture

This bitten me during EFQ v2 although figured out fairly quick:


      $entity = entity_create('test_entity', array(
        'ftid' => $i,
        'ftvid' => $i,
        'fttype' => $bundles[$i & 1],
      ));
      $entity->enforceIsNew();
// This is new. Your revisioned entity won't load without this! Because ftvid is set it tries to update a revision which doesn't exist. Without enforceIsNew it tries to update a whole non-existing entity so not a new pattern though.
      $entity->setNewRevision(); 
      $entity->save();
webchick’s picture

We're once again over the critical task threshold. Please try and find time to write up documentation for your API change ASAP so your fellow contributors' features aren't blocked. Thanks.

moshe weitzman’s picture

Yes, please write the Change Notice

But it is over the top to use Critical priority for this. IMO, the Needs change notification tag is sufficient. We will remember to close those out before release.

Berdir’s picture

Status: Active » Needs review

Sorry for taking so long, here is the change record, please review: http://drupal.org/node/1818376.

Render controller is next, will try to find time to write that one today.

webchick’s picture

Status: Needs review » Fixed

Looks good to me; thanks Berdir!

Tor Arne Thune’s picture

Title: Change notice: Support for revisions for entity save and delete operations » Support for revisions for entity save and delete operations
Priority: Critical » Normal
Issue tags: -Needs change record
mitchell’s picture

Status: Fixed » Needs review
FileSize
393 bytes

This is a small fix to entity_revision_delete()'s comment. (I thought better here than a new issue.)

Status: Needs review » Needs work
Issue tags: -Entity system, -revision

The last submitted patch, entity-revision-save-delete-1723892-99.patch, failed testing.

fubhy’s picture

Status: Needs work » Needs review
Issue tags: +Entity system, +revision
Berdir’s picture

Status: Needs review » Reviewed & tested by the community

Upsie.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed to 8.x, but let's get follow-up issues for minor things like this, ok? :)

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

Anonymous’s picture

Issue summary: View changes

Updated issue summary.