Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Currently the provided CRUD controller does not yet support revisions.
Battle plan:
* Add another controller class inheriting from the EntityAPIController, so we don't need to bother changing stable code.
* Provide a set of useful API functions, entity_delete_revision(), ..?
* Implement tests.
Questions:
* Should the entity type specify which properties are revisioned? Should it have to create the table, or should we auto-create it with the same properties as the main one?
Comment | File | Size | Author |
---|---|---|---|
#145 | entity_revisions.patch | 28.05 KB | fago |
#144 | entity_revisions.patch | 27.45 KB | fago |
#139 | entity_revisions.patch | 27.33 KB | fago |
#131 | entity-9966969-revisions-131.patch | 26.43 KB | indytechcook |
#133 | entity-9966969-revisions-132.patch | 26.43 KB | indytechcook |
Comments
Comment #1
Mark TrappTagging.
Edit: er, I guess the Entity CRUD API - main component no longer exists, so it defaulted to Core integration. Apologies if it's supposed to be in a different component.
Comment #2
mikey_p CreditAttribution: mikey_p commentedMarked #1113032: EntityAPIController's save() method does not appear to even try to save revisions? as a duplicate of this issue.
Hi, I'm planning to start working on this feature (I did a quick hack a few months ago to test this feature, and it seems like we want to go with Entity API for RedHen CRM). It seems you've outlined a basic plan already, if I were to start work on this, would you like to see patches in this issue, or links to a sandbox on d.o or github?
Personally, I'd lean towards making all properties on an entity revisioned for now. I didn't know that Entity API handled schema creation for it's entities. I 'm not sure about making all the revision table schema match the base table, but it seems like that would be the simplest approach for now.
Any other considerations before starting work on this?
Comment #3
Damien Tournoud CreditAttribution: Damien Tournoud commentedWe are going to need this, so here is a starter patch:
$entity->revision
is true;Still missing is adding support for deleting revisions.
Comment #4
fagoLooks good + building upon the existing stuff makes sense to me.
We need to update and improve the docs, e.g. updating the README to tell people how to use it. The revision flag could be documented at entity_save().
># I followed what the Node module does: a new revision is created only when $entity->revision is true;
Yep, let's just follow the node module and also implement a similar entity_revision_delete() function. However, I guess we need to document $entity->delete() always deletes the whole entity and does never operate on the revision level like save().
Then, I guess an $entity->isRevision() helper would make much sense too - so one is able to determine whether saving the changes is just updating an old revision, creating a new revision or just updating the recent revision?
Unrelated, an entity_is_new() API function or according method would make sense to me too.
Also, the 'revision' key might be confused with something like an isRevision() method(). However it doesn't say whether the entity object represents an revision, but whether a new revision should be created. So maybe 'is_new_revision' analogously to 'is_new' would make more sense?
Anyway, let's make sure we have a complete solution and get some more reviews before we commit it. So we can ensure the solution makes somehow sense ;) I don't think the d7 entity API is the place to come up with an ideal entity revision API, let's do that in d8. As said, let's stick to something similar to node revisions that makes sense for D7 - but still, let's try to don't unnecessarily confuse developers and maybe do some small improvements like renames if that helps developers.
Maybe we wanna use a sandbox project to ease tracking changes?
Wouldn't it make more sense to use $entity->original->revision_key to access the old revision id now? Not sure whether it works that way for nodes as of now though.
@tests:
I guess we should also test whether updating an existing revision works properly. Maybe there are some node related revision tests we can take over and generalize?
Comment #5
dixon_The patch in #3 didn't apply anymore, so here is a plain re-roll of it. Unfortunately I don't have time to address the issues mentioned in #4 by fago.
But, the patch works perfectly for me so far. I will try to find time checking back on this, so we can get this in, would be awesome!
Comment #6
fearlsgroove CreditAttribution: fearlsgroove commentedThere needs to be a way for implementations to shuffle properties around before saving the revision record. The specific use case, when following the node paradigm, would be that "created" and "changed" on the node are simply "timestamp" on the revision, and that we want to track the revision "uid" separately from the node's author. Such examples are likely to be common even in non-node situations.
I'd prefer a solution where a preSaveRevision method is added to the controller class, as that's more convenient to implement than a hook imo.
Comment #7
fearlsgroove CreditAttribution: fearlsgroove commentedAttached patch builds on #6, adding support for a protected (overridible) method on the controller that allows base classes to perform some preparation on the revision record before it's written. Specifically this would support the use case of users in node, where you'd like the UID of the revision to be set, but not change the UID of the core record.
It also adds support for properly deleting entities. The previous patch left orphaned revision records. Both scenarios probably need tests.
Comment #8
fearlsgroove CreditAttribution: fearlsgroove commentedTwo examples of overriding the saveRevision method in the entity controller:
Sets the UID of the revision object based on a separately set property that's not an actual schema field:
.. or based on the current user:
edit: use php instead of code
Comment #9
Fidelix CreditAttribution: Fidelix commentedCan I have revision support exclusively for the embedded field collection with this patch in #7?
If yes, any extra steps for accomplishing it?
If no, what still needs to be done for this?
Comment #10
fearlsgroove CreditAttribution: fearlsgroove commented@Fidelix: Field collection module would need to be updated with support for revisions. this patch doesn't enable revision support automatically for all entities that use entity api, it just enables entities to fairly easily support revisions if they want to. Not likely any modules will get revision support until this or something similar actually lands. I'm sure it'd be quite welcome in some fairly big modules (commerce)
Comment #12
tutumlum CreditAttribution: tutumlum commentedsubscribing
Comment #13
Anonymous (not verified) CreditAttribution: Anonymous commentedsubscribing
Comment #14
Fidelix CreditAttribution: Fidelix commented@wildkatana, Stop subscribing, start following
http://drupal.org/node/1306444
Comment #15
jstollerPlease make sure that entity revisions are implemented in such a way that the techniques being employed to moderate content—by modules like Revisioning, Workbench Moderation and State Machine—can be used to moderate other entity types as well. They should be able to separate the "current" revision from the "latest" revision. My own understanding of how this all works is minimal, so please forgive me if this request is out of place.
Comment #16
jstollerOops. Removing random tag.
Comment #17
MacRonin CreditAttribution: MacRonin commentedI did a follow, but updating issue title so it more informative when seen in the Dashboard activity display.
Comment #18
ygerasimov CreditAttribution: ygerasimov commentedHere is rerolled patch based on #7 with some changes.
I have implemented according to comments of #4 following items:
- entity_revision_delete()
- renamed 'revision' key to 'is_new_revision'
- expanded tests (there are not much good examples of tests in node module about revisions)
- removed $entity->old_revision_id as it never used
- added key $entity->set_active_revision that set revision to be active on $entity->save()
- small update of documentation
@fago, I don't understand your comment about $entity->isRevision(). Could you please explain in more details what do you mean this method should do? And when we should use it?
Comment #19
fagoHere a first (incomplete) review, it should give already some input though. Unfortunately there a lots of glitches and inconsistencies in current revision handling, what makes this rather hard :/
Should be "Deletes an entity revision."
Shouldn't that be integer?
The ID the revision .. - make full sentences.
Missing documentation of the return value + missing an empty line before @return.
I think it should better be entity_revision_delete() - analogously to node_revision_delete().
We should add a "delete revision" callback support analogously to entity_delete(). Also, we need to
* update docs
* update entity_type_supports()
* add node module support
?
Ouch. Let's internally use 'revision_delete' as hook to match the function name and make the exception for the attacher only.
As for entity_revision_delete().
That won't cover the field api :/
Why not save the revision first to avoid having this extra-update?
Hm, maybe we should make that public and part of a revisionable interface?
What about doing entity_revision_save() to allow for saving a new, non-current revision?
We'd have to fiddle-around with field-API to make it work though.
This should probably replace the $entity->set_active_revision key though. Also, it means we should have a hook "entity_revision_save" for it.
isRevision() should tell me whether $entity is the *current* revision or not, so maybe isCurrent() or isCurrentRevision() would fit better.
Comment #20
ygerasimov CreditAttribution: ygerasimov commented@fago thank you very much for the review!
• Fixed doxygen comments.
• Renamed entity_delete_revision to entity_revision_delete
• Renamed deleteRevision to revisionDelete
• I do not understand what means 'We should add a "delete revision" callback support analogously to entity_delete().' In controller revisionDelete() we invoke 'revision_delete' hooks.
• Updated entity_type_supports()
• Don't understand what 'node module support' we should add here.
• Hook invokation, renamed 'delete_revision' to 'revision_delete' and made exception for field attacher only.
• Don't understand comment about 'covering field api'.
• Controller save method is built according to node_save, so it updates main table after creating revision if it is needed. So everything looks consistent to me regarding 'Why not save the revision first to avoid having this extra-update?'
• I would suggest to keep saveRevision method protected as we would like new revisions created using save method with setting additional keys: is_new_revision and set_active_revision. Please see _node_save_revision() it is not really meant to be used directly.
• I have implemented isCurrentRevision() and added test for it. It does direct query to database to check whether revision is current.
Comment #21
trevjs CreditAttribution: trevjs commentedThanks for this. I tested this out with a module I'm working on, and it seems to be doing the job for now. Proceeding with caution however.
Also, the revisions for a body field on the entity I'm using it with seems to be saving correctly. I'm going to set something up with my test module tomorrow for restoring revisions. I don't foresee any problems.
Comment #22
trevjs CreditAttribution: trevjs commentedI've run into a problem with custom entities with the organic groups group field. OG tries to load the newly created entity when its insert hook is invoked, but can't. Would you say this is a problem with OG or with this patch? Not sure what should be happening here to make this work. Should we be caching the newly created entity? Or can the invoke be moved outside the transaction?
Lines 432 through 441 of entity.controller.inc:
Comment #23
ygerasimov CreditAttribution: ygerasimov commented@trevjs, lets not mix this issue with integration with OG issue. Could you please open a new issue for this? I would love to investigate so can you please also publish module that creates your custom entity and write instructions how to reproduce the problem.
Comment #24
wjaspers CreditAttribution: wjaspers commentedPatch #20 applies cleanly, although I havent seen any instant effects. Will have to test integration on top of other modules.
Comment #25
rooby CreditAttribution: rooby commentedJust a quick pass over and all I have to note is that there are a lot of whitespace fixes that are unrelated to this issue. Although if fago doesn't mind then it's irrelevant.
There are also a couple of indentation issues:
I will have a proper test on a website sometime in the next day or so and give proper feedback then.
Comment #26
rooby CreditAttribution: rooby commentedI threw together a quick patch for profile2 to go along with this and got revisions to work with no errors or anything yet.
It is very basic and I have not tested much yet but I'll continue tomorrow.
The patch is at #1043128: Profile revisions
Comment #27
fubhy CreditAttribution: fubhy commentedIt would be easier to review this patch if you didn't fix all kinds of stuff that doesn't belong to this issue with it :-).
Should read "Deletes an entity and all its revisions".
Should read "Deletes an entity revision."
Let's remove the "integer" part (@param integer ...) as we don't do that anywhere else either :).
The @return is also not correct. a) There is no "return TRUE;" at all and b) It could be a little more descriptive like: "TRUE if the entity revision could be deleted, FALSE otherwise." or something like that.
Also, I think that it would make sense to return TRUE even if no entity revisions could be loaded because technically that would mean that the entity revision with that id never existed or has already been deleted which is actually what we want to achieve... But that is just my 2 cent :).
Okay, good idea... But where is that separate property? :)
This one needs a documentation block.
The indentation is wrong here (in 'main' and 'test2').
Lets use single quotes here.
Here too.
Should read "Make use of the class label ..." (remove single quote and add a 'of').
Comment #28
logaritmisk CreditAttribution: logaritmisk commentedRerolled patch based on #20 to get patch to work with drush make again and with some changes based on fubhy review.
Comment #29
fubhy CreditAttribution: fubhy commentedEven though there obviously are whitespace issues currently we shouldn't incorporate the fixes for that in this patch. Let's do that in a separate issue. This is only one short excerpt of the whitespace issues that you are fixing in this patch but you should remove all of those fixes. Please put them into a separate patch in a separate issue. :)
@return is missing in the PHPDoc block. Please also remove the "integer" declaration for @param $revision_id, we don't use that usually, as mentioned before.
Why do you create a new variable $field_attach_hook here? Just keep using $hook. Like so:
This is also unrelated to this issue. Maybe incorporate that in the same issue / patch for fixing the whitespace issues?
Ok... You are fixing it here (which is unrelated to the patch)... But...
... You are not fixing it here :)
Comment #30
fubhy CreditAttribution: fubhy commentedJust a suggestion: It is much easier for people to review your patches if you keep on topic with the code. That means: Don't fix unrelated stuff (e.g. those whitespaces or unrelated [probably misspelled or incorrect] documentation). That way the git log remains clean and we can tackle one issue after the other.
Other than that (and the stuff mentioned in my review) the patch looks good. Thanks!
Comment #31
logaritmisk CreditAttribution: logaritmisk commentedUpdated patch based on fubhy's review.
I don't know, but It seems that the original $hook is needed later so if we override it once, we need to override it again later to revert, like this:
and that's confusing.
Comment #32
logaritmisk CreditAttribution: logaritmisk commentedOups, forgot to change status.
Comment #33
fubhy CreditAttribution: fubhy commentedOkay, cool... I didn't know that $hook was used after your code-changes because I only looked at the patch and not at the function itself ;). I guess its fine then. Only thing that I noticed by looking at the patch ones more is this (the code itself looks good, but I still have to give it a proper test-run):
Let's use proper english. Even in short code comments like this.
"Only update the base table if the entity doesn't have revisions or we are updating the active revision."
"Check whether this is the current / active revision of the entity."
Or something like that.
Make use "OF" the class label ...
Comment #34
logaritmisk CreditAttribution: logaritmisk commentedOne more try :)
Comment #35
fubhy CreditAttribution: fubhy commented"In node_revision_delete() core invokes hook_node_revision_delete() and hook_field_attach_delete_revision(), so we need to adjust the name of our revision deletion field attach hook in order to stick to this pattern."
Or something like this.... Sorry I must've missed that part in my first review :(. Thanks for the patch, everything else looks good now.
Comment #36
logaritmisk CreditAttribution: logaritmisk commentedOne more try, again :)
Comment #37
John Pitcairn CreditAttribution: John Pitcairn commentedIf we're being proper, I'd argue that "only" is redundant (and ugly at the start of a sentence). "If" is quite specific, "only" does not add meaning.
"Update the base table if the entity doesn't have revisions or we are updating the active revision."
Comment #38
Anonymous (not verified) CreditAttribution: Anonymous commentedBesides the spelling how's this feature looking right now?
Comment #39
rooby CreditAttribution: rooby commentedI've been using entity revisions using these patches for a little while now with nothing obvious going wrong (it isn't a live site yet though so very low traffic).
It would be good to get a new review from fago to see what he has to add.
Comment #40
fubhy CreditAttribution: fubhy commentedMaybe we should change that one sentence as pointed out by #37. Other than that it is working and looking good to me now.
We will have a BoF and some code sprinting @ Denver and hopefully a stable release before or during DCon. Hopefully this patch will make it into that.
Comment #41
logaritmisk CreditAttribution: logaritmisk commentedI've changed the comment to #37 suggestion.
Comment #42
fubhy CreditAttribution: fubhy commentedLet's leave it at RTBC then so fago can take a look.
Comment #43
Anonymous (not verified) CreditAttribution: Anonymous commentedCan we get this tagged as 'D7 stable release blocker' so it'll make it to 1.0 ?
Comment #44
rooby CreditAttribution: rooby commentedI agree. Tagging (fago can remove if he doesn't want it so).
Comment #45
fagoThis misses documentation in entity.api.php
Not every entity type based upon the CRUD controllers supports revisions - they are optional. The return should reflect that. Also, what's the return if the revision deletion info is available?
Also, revisionDelete() is not part of the interface - thus the check is invalid. I think we'll have to define another interface for making the controller revisionable, e.g. EntityAPIRevisionableControllerInterface which extends the EntityAPIControllerInterface.
Hm, I think that should be much more a separate function and/or a method on the entity object. Also, we should try to preserve that information when *loading* the entity so we don't have do any query when checking for it.
There is no documentation for the 'set_active_revision' key nor is it possible to customize the name for it. We'll should add an 'entity key' for that + add in the entity-key information for nodes (what makes entity_save() + the key saving revisions generally work).
The problem with that one is, that the field api always uses the *latest* revision as "current" revision - so the "set_active_revision" wouldn't be applied. Thus, we cannot really support "set_active_revision" without having to save at least the field api information twice. *ouch* Still, I think this is the best we can do.
@"D7 stable release blocker"
As this is a feature addition, I don't think it has to block the stable release. I'm happy to add this before the release if it's getting ready in time, however I don't think it should postpone the other stuff becoming stable.
Comment #46
jstollerSo how will this work for people using State Machine, Workbench Moderation, or any other module that separates the current revision from the latest revision? Does this patch support that?
Comment #47
rooby CreditAttribution: rooby commentedfago goes into that briefly towards the end of #45.
Comment #48
jstoller@rooby: I'm looking for clarification. I have only a minimal understanding of this API, but I have a vested interest in entities being both revisionable and moderatable. I was hoping for a somewhat less technical assessment of the state of Entity API in this regard, assuming this patch is committed.
Comment #49
rooby CreditAttribution: rooby commentedI believe what he was saying it that the way this patch currently sets the active revision will not work properly with field API.
He then gives an idea for a solution to that problem that has a negative aspect of having to save field API data twice but will still work.
So non-technical answer is, not properly supported in the current state of the patch, but hopefully entirely supported with a few changes to the patch.
Comment #50
indytechcook CreditAttribution: indytechcook commented@jstoller, those modules are responsible for taking care of the node revision updates themselves. Entity API module should respect what core does, not what we want it to do.
Comment #51
jstoller@indytechcook, Core allows for the vid of a node to be pointed at an older revision when it is saved, thus permitting these modules to separate the current revision from the latest revision. I've always considered this a bit of a hack, but never the less, this hack is the only thing allowing for content moderation in Drupal. I want to make sure the same technique can be extended to other entities created with Entity API.
For instance, if this patch gets committed and Beans are made revisionable, then will Workbench be able to moderate beans without too much work? Will content moderation modules be able to have a general solution for all revisionable entities based on Entity API, or will they need unique solutions for each entity?
Comment #52
rooby CreditAttribution: rooby commentedAs I said:
So non-technical answer is, not properly supported in the current state of the patch, but hopefully entirely supported with a few changes to the patch.
Comment #53
indytechcook CreditAttribution: indytechcook commentedHi @jstroller, thanks for you comments, let me clarify my statements a little.
While it possible to make a new revision that isn't the published revision, it does not work correctly with fields. Fields expect the newest revision to be the publish revision.
I wrote the beans module and help maintain the state machine module. Both State Machine (State flow) and Workbench moderation have to do some nasty tricks to keep the newest revision as the latest. Each time the node is saved, it has to check if the revision being saved is the newest and published. If it isn't it has to reload the published revision and resave that.
I think I understand what you are saying. Let's use Entity API to do this behind the scenes to do what these other modules are doing themselves? While I think this concept is a good idea, Fago has generally be against changing how core works.
Edit:
FYI. I can't wait for this patch to get in. It's so important.
Comment #54
jstoller@indytechcook, while I think it would be great if Entity API made content moderation easier, my primary concern is just that this doesn't make it any more difficult for State Machine to do what it does. I'm planning to use State Machine on a project and I'd like to use it with Beans, but I'd also like to use it with other as yet undefined entities.
Comment #55
ygerasimov CreditAttribution: ygerasimov commentedI would like to update everyone with current status of this patch (see attached).
Tasks done:
1. Updated documentation.
2. Added interface EntityAPIControllerInterface.
3. Now check about whether entity is current revision is done on load.
4. Entity key 'set active revision' added to customize property of the entity that determine whether new revision should be current.
5. Test rewritten completely. Now it uses title text property so debugging is much more pleasant.
6. I have added Field API text field to entity in the test that breaks test completely. This proves @fago quote about Field API won't work. At the moment I am not quite understand solution, but will work on it. If anyone can point me to the right direction I will very appreciate (like @fago advised save field information twice).
Comment #56
Anonymous (not verified) CreditAttribution: Anonymous commentedIf i remember correctly I think I saw a new revision created when trying to revert to previous one. So thats how node does it.
Comment #57
crimsondryad CreditAttribution: crimsondryad commentedHey, we need this to work for field_collection revisioning. It looks like @ygerasimov has stalled. Can you please provide a status update and where we can help?
Comment #58
ygerasimov CreditAttribution: ygerasimov commented@crimsondryad welcome to help. The problem I have now is fields added to revisions. Please check the failing test.
Comment #59
tim.plunkettLets see the failures
Comment #60
vasikeRules failure
I tried to add a new Rule without success and i got this log message
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'id' cannot be null: INSERT INTO {rules_trigger} (id, event) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1); Array ( [:db_insert_placeholder_0] => [:db_insert_placeholder_1] => node_presave ) in RulesEntityController->storeEvents() (line 173 of /drupal_path/sites/all/modules/contrib/rules/includes/rules.core.inc).
Comment #61
rooby CreditAttribution: rooby commented@vasike:
Are you saying you did not have this error, then you applied this patch in #55 and now you have the error?
Comment #62
vasikeexactly. sorry if i wasn't so accurate.
i am using the last Rules release, 7.x-2.1
after i downgraded to the last one Entity API release, 7.x-1.0-rc2, it worked.
Comment #63
Anonymous (not verified) CreditAttribution: Anonymous commentedSo how are the revisions looking right now ? What's the current status ?
Comment #64
rooby CreditAttribution: rooby commentedComment #65
rooby CreditAttribution: rooby commentedTrying to get the test results.
Comment #66
ygerasimov CreditAttribution: ygerasimov commentedHere is another version of the patch. Now Field API works properly.
In case new revision to be created that should become active or not active revision is updated, we invoke field_attach_update() two times now.
All tests pass!
Welcome to review.
Comment #67
rooby CreditAttribution: rooby commentedThanks ygerasimov!
I will be trying this out in the next day or two.
Comment #68
lathan#66 is throwing
A Question, Do we need to up date our entities to have any additional db cols? for the rid? not quite sure how thats working here, or is entity api handling creating a revision table?
Comment #69
rooby CreditAttribution: rooby commented@jucallme:
Yep. Modules that implement entity revisions need to update their schema accordingly.
You would have a revision database table to go with your entity table in a similar fashion to how drupal has a node and a node revision table. (with an added rid column in the main entity table.)
Also, see the tests included in this patch and its entity_test_revision table.
Comment #70
dagmarJust as a reference. Automated test will not be executed until this be fixed #1450686: automated tests fail.
Comment #72
fubhy CreditAttribution: fubhy commented10 days later... :)
Comment #73
ygerasimov CreditAttribution: ygerasimov commentedRerolled patch attached. Problem was in README.txt :)
Comment #74
crimsondryad CreditAttribution: crimsondryad commentedYay! Thanks @ygerasimov!
Comment #75
sjf_ddev CreditAttribution: sjf_ddev commented#73: entity-996696-revisions-73.patch queued for re-testing.
Comment #76
Kristen PolCan anyone provide some instructions on how best to test this patch? Or, perhaps it can't be tested (manually) since it's just an API change? The Field Collection and Bean modules can't get revisions in until this patch is committed and I'd like to help speed that up if possible. Thanks!
Comment #77
HyperGlide CreditAttribution: HyperGlide commented@Kristen Pol -- Thanks
Hope this can be tested and committed soon -- would very much like to have revisions within field_collections.
Comment #78
rooby CreditAttribution: rooby commented@Kristen Pol:
Someone could implement a patch for support for revisions in those modules that build on the changes in this patch.
I did that with profile2, although the patch is for an old version of this patch and has a few issues, but you get the idea - I need to update that patch.
Comment #79
Kristen PolI don't know the Entity API or the Field Collection (FC) implementation so I am not the best person to try to do the FC patch. Though maybe I will need to try out of necessity.
Comment #80
Kristen PolWhen applying the patch from #73, I get an error on the README.txt file:
I've attached the .rej file.
Comment #81
tim.plunkettIt applied cleanly for me, @Kristen Pol were you using the latest dev version?
Comment #82
Kristen PolGood call, @tim.plunkett. Looks good when applying to *dev*.
Btw, I have applied the patch (#73) and am starting to patch the Field Collection module to use revisions but am at a point where I need some feedback in terms of direction:
http://drupal.org/node/1031010#comment-6134700
Feedback is very welcome! I would love to get a patch finished early this week if at all possible.
Comment #83
Hydra CreditAttribution: Hydra commentedFor me the patch applied clean! Also the functunallity worke'd as expected. It would be good if a more experienced developer would take a look at it to get this RTBC!
Comment #84
fubhy CreditAttribution: fubhy commentedI had to read this multiple times before I finally understood what exactly it does. Can we rephrase that to be a little bit more descriptive? Also, please make sure that the grammar is right (articles, etc.).
Here you named it 'deletion revision callback' and in other places you named it 'revision deletion callback'. To me, the second version makes more sense. Please make sure that it is the same everywhere.
See above.
This doesn't really belong in the patch. It doesn't really matter in this case but you should try to stay on topic when creating a patch. Just a hint. :)
What does it return when the entity revision was deleted? Also, please make sure that the grammar is right. (were / was, etc.)
Maybe better rephrase it to something like "FALSE if the entity type doesn't support revisions."
However, I think that in that case it should return NULL anyways because if the entity type supports revisions and the entity revision could be deleted it returns FALSE as well.
Also, the
else
is not required here.The code style fixes are getting a little bit out of hand here. This should really be fixed in a separate issue.
I nearly missed this, but the "." exceeds the 80 characters limit :P. Sorry buddy! :)
The
else
is not required here either. It doesn't reach that point in code anyways if the previousif
statement evaluates to TRUE.Comment #85
Kristen PolI have updated the issue summary for the Field Collection module revision support:
#1031010: Support revisions for field collections
which is being built upon the Entity API patch here.
It would be great if someone who's comfortable with this Entity API patch (@fubhy ?) to take a look and review and comment on the latest Field Collection patch available.
Comment #86
cosmicdreams CreditAttribution: cosmicdreams commentedI'll try to pickup at where #84 leaves off this week if I have time.
Comment #87
wizonesolutionsRerolling this right now.
Comment #88
wizonesolutionsTests are still running locally, but testbot will probably be faster. I made all the changes requested by fuhby - undid out-of-place style fixes, changed
FALSE
toNULL
in that one function, removed unnecessary else statements, clarified whatset active revision
does.Comment #90
wizonesolutionsOops. OK, let's try this.
Comment #91
fubhy CreditAttribution: fubhy commentedThis line is a left-over I think :).
There should be a newline before @return as well as between the interface declaration and the doc block of the first function in the interface.
Comment #92
wizonesolutionsThanks fuhby for the review. Try this one.
Comment #93
fubhy CreditAttribution: fubhy commentedNevermind... I was still asleep :)
Comment #94
fubhy CreditAttribution: fubhy commentedI would love to see some integration in the Views and Metadata controllers too!
Comment #95
ygerasimov CreditAttribution: ygerasimov commented@fubhy, can we get this patch committed first and then implement new features like views and metadata controller? This patch is hanging here for really a long time and a lot of people are eager to have it landed. Lets create separate issues for new features.
Comment #96
fubhy CreditAttribution: fubhy commentedI am fine with that... I need it too for my GSoC project.
Comment #97
wizonesolutions+1 on committing. Field Collection really needs this too.
Comment #98
jhodgdon+1 on filing separate issues for other feature requests and not trying to mix them into this issue.
Comment #99
fubhy CreditAttribution: fubhy commentedThis is not a separate feature request. Instead, it is a very valid request for integrating the new code with existing parts of the code within the same module. This is a must have addition to THIS patch and not a separate feature request. I need this patch commited as well for my own project but what I requested here is something that I consider a must-have addition.
It's up to fago to decide whether he wants to commit this without that. I am fine with both.
Comment #100
massud CreditAttribution: massud commentedI tried the patch provided in #92 in the profile2 module but I am getting the following error:
Notice: Undefined property: Profile::$vid in drupal_write_record()
I think this is caused by the following code in EntityAPIController::save():
Am I missing something?
Comment #101
massud CreditAttribution: massud commentedFollowing up the problem mentioned in #100, the revisionKey of $entity must be set to NULL instead of unsetting:
Though, unsetting should work in drupal 8. (refer to the drupal_write_record() implementation of drupal 8 here: http://api.drupal.org/api/drupal/core!includes!schema.inc/function/drupal_write_record/8).
Comment #102
rooby CreditAttribution: rooby commented@massud:
How are you doing it with profile2? Are you using the patch at #1043128: Profile revisions?
Because the patch I did there has a couple of issues and is for an older version of this patch and needs to be updated.
Comment #103
massud CreditAttribution: massud commented@rooby,
I have developed a new patch based on yours. The problem comes from the fact that the property_exists() function of PHP returns TRUE for an "unset" property of a class instance. A piece of code has been added to the drupal 8 implementation of drupal_write_record() to take care of it.
Comment #104
massud CreditAttribution: massud commentedAlso it would be very helpful to have an "entity_revision_list" function.
Comment #105
massud CreditAttribution: massud commentedI am experiencing the problem mentioned in #60. I traced the code and figured out that this problem is caused by the changes made in the save() method of EntityAPIController class:
Previous implementation:
New implementation:
Rules module does not set the is_new property. So in previous implementation, the else block is executed and entity is saved in the database. But in new implementation, entity is never saved in the database since is_new is not set.
Comment #106
alanburke CreditAttribution: alanburke commentedTesting the Field collection patch in tandem with this patch.
Hit the error at http://drupal.org/node/996696#comment-6187452
and resolved using the suggestion at http://drupal.org/node/996696#comment-6189344.
Working well
Comment #107
ktaiwo CreditAttribution: ktaiwo commented#73: entity-996696-revisions-73.patch queued for re-testing.
Comment #108
scottrigbyRe #92, one question I have is - should the latest entity revision not also be saved to the base table? Currently only the revision ID is updated in the base table on a new revision.
Temporarily I've worked around this by in a hook_{ENTITY_TYPE}_update() but that's kind of silly:
I would add this in a new patch, but the current code seems to go to some pains not to update the base table - and somehow I wonder if I'm missing something about this.
Comment #109
fagoI don't think that unset() should be necessary. It's not for node_save() either. Let's just unset it ourself if the is_new_revision flag is set and go without the unset() here.
Testing this is a good idea, but it should load the not active revision first and verify that this works as well.
This should mention how it behaves with active revisions.
node? this should talk about entities, not nodes.
This comment should just say it implements the interface, as others.
Terminology mismatch. We use *active revision*, not current? Also, this is in quite some other places. Note, see related d8 discussion: #1643354: [Policy, No patch] Overhaul the entity revision terminology in UI text.
Then, isactiveRevision() should not be a method on the entity controller. Instead, there should be helpers isactiveRevision() and getRevisionId() in the Entity class (analogously to #1612014: Create an interface for revisionable entities) as well as procedural equivalences that work with all entities (node as well).
That's gone, so should be the comment.
On insert, it must always be the active revision, not? We cannot have an entity without an active revision. Also, that should be documented at the active revision key.
hm, what? I don't get that. Please improve the docs so it explains what happens here and why.
This can be shortened by using !empty() in the first clause (twice).
Why do we reset the cache here again?
Documentation @return does not match reality. FALSE !== NULL. Also, it always saves something?
Then, let's simplify that check by setting $entity->is_new_revision at the beginning of our save operation when it is an insert.
For the sake of moving on with this, let's postpone further integration with the views and metadata stuff to follow-up issues.
Comment #110
fagoOh, and of course we need to fix #100 as well + add tests to cover this case too.
Comment #111
stella CreditAttribution: stella commentedI got a similar error to the one in #100 except with the patch for the field collection module from #1031010: Support revisions for field collections
The change suggested in #101 fixed it for me. Patch re-roll just for that change attached.
Comment #112
alexweber CreditAttribution: alexweber commentedgo testbot
Comment #113
indytechcook CreditAttribution: indytechcook commentedAdding a tag to track this issue as part of the LSD/CSI project (http://groups.drupal.org/large-scale-drupal-lsd-projects-and-plans/conte...)
Comment #114
wizonesolutions#111: entity-996696-revisions-111.patch queued for re-testing.
Comment #115
indytechcook CreditAttribution: indytechcook commentedThe patch looks good. I have it working well with beans: http://drupal.org/node/1335494#comment-6335816
Great job everyone.
Comment #116
jordojuice CreditAttribution: jordojuice commented<--- Late comer to this issue!
First of all, big +1 for revision support, it will help me a lot at work. And on a side note, thanks for all the hard work @fago and others, Entity API has saved me plenty of time at work already. Any interest in supporting reverting an entity to a previous revision? This is what I'm working on right now, so I'd be glad to help contribute it here or on top of this patch in a separate issue.
Isn't
EntityAPIControllerRevisionableInterface::getCurrentRevision()
supposed to beEntityAPIControllerRevisionableInterface::getActiveRevision()
as per fago's comments in #109? The terminology is indeed inconsistent, and there are some other variables and documentation that need to be fixed.The
isCurrentRevision()
/isActiveRevision()
method returns$entity->currentRevision
, a boolean that's set when the entity is loaded. This means if the load method is overridden the overriding method needs to be sure to set the currentRevision/activeRevision property. That means more chance for error. Loading properties into the entity object that could later be required by another controller method just seems like bad practice to me, but maybe I'm wrong and maybe it should at least be documented if theisActiveRevision()
method will use that property. Also, the name of the property is a little misleading. I would assume that it stores the active revision ID, not a boolean flag indicating whether this is the active revision for the entity.$entity->activeRevision
and$entity->isActiveRevision
are two entirely different things.EDIT: By the way if no one gets to it I will try to put together a new patch tomorrow :-)
Comment #117
BerdirThe currentRevision flag is exactly how it's implemented in Drupal 8 and I think it makes sense to be consistent.
Comment #118
jordojuice CreditAttribution: jordojuice commentedYou're right about that. Touché for consistency, though ignoring it, I think it stills seems to me less stable without standard flags being commonplace in entities. Generally the entity API allows developers to specify the data that is expected in an entity via the 'entity keys' array and entity property info with Entity API. But now if a
stdClass
or other entity is created with thenew
keyword the developer may need to set a flag as well, and perhaps the create() method should set it as well..The "current" terminology still needs to be changed to "active" though, as per #1643354: [Policy, No patch] Overhaul the entity revision terminology in UI text
Comment #119
jordojuice CreditAttribution: jordojuice commentedSpeaking of which, the patch at #218755: Support revisions in different states is now using completely different terminology with the
isDefaultRevision
flag andisDefaultRevision()
method (which emphasizes my point thatcurrentRevision
andisCurrentRevision
properties say two different things to me as a programmer).At the very least
$entity->currentRevision
is a little misleading.Comment #120
wizonesolutionsjordojuice: Reverting works - check out #1031010: Support revisions for field collections (though I am not sure if that's field_collection's implementation to thank or Entity API itself).
Comment #121
jstollerFor clarity...
The Default Revision is the version that will be selected if you load an Entity by ID for viewing, but do not specify a version. node_load($nid); gets back whatever the "default" version is, which may or may not be the most-recently-edited.
The Active Revision is the version that will be selected if you load an Entity by ID for editing, but do not specify a version. Note that this may or may not be the same as the Default version.
Currently Drupal Core thinks Default=Active=Latest Revision. However, modules like Workbench Moderation, Statemachine and Revisioning, split these into separate concepts. The current patch in #218755: Support revisions in different states aims to codify these distinctions in Core, making content moderation more pervasive and easier to implement.
If you want to be consistent with these advancements, then really you should implement both
getActiveRevision()
andgetDefaultRevision()
methods. At this point,getActiveRevision()
should return the latest version in the revision table for an entity, whilegetDefaultRevision()
should return the version referenced in the entity's base table. I think that should allow this to work as expected with current revisioning implementations.Comment #122
Anonymous (not verified) CreditAttribution: Anonymous commentedSo what does one have to do to finally be able to use revisions?
Comment #123
HyperGlide CreditAttribution: HyperGlide commented@ivanjaros +1
Comment #124
rooby CreditAttribution: rooby commentedIt depends what you want to do revisions for.
This provides the API to be able to do revisions.
Then any module that creates entity API entities has to handle its own revisions.
So for example, if you look at modules like field_collection and profile2, they have their own issues for revisions, which require this patch for entity api and a patch for their own module to implement their revisions.
Comment #125
HyperGlide CreditAttribution: HyperGlide commentedThink it is clear that:
I believe the desire is to help close this issue and commit a patch that allows the other modules like field_collection and profile2 to progress with implementing revisions respectively.
How can we help to move this along from its' current state of
needs work
tocommitted
?Thanks for all the developers hard work and do hope we can have a solid patch to commit soon.
Comment #126
Anonymous (not verified) CreditAttribution: Anonymous commented#124 I know that. I've used Entity API to create many custom entites. I'm asking what I need to do, other then usual, to be able to use revisions.
Currently I have a revisions table for my entity which is defined in hook_entity_info and I have VID field that connects the revisions with the entity(I've defined it in hook_entity_info in 'entity keys' as 'revision' => 'vid', same as node module does it). I've tried to save my entity with 'revision => 1' but it didn't worked(that's how node module does it). So I'm asking what else do I have to do to be able to use revisions? I should be clear that I ment it from programatical point of view.
Comment #127
stella CreditAttribution: stella commentedThis patch, combined with the one for field collections at http://drupal.org/node/1031010 was working great, until it came to file fields on field collections. In that situation, when creating a new draft revision, the images and files within a field collection on the published revision were deleted. :(
After a bit of debugging, I tracked down the problem to file_field_update(), where it has this snippet of text:
However, for field collection entities, there was no $entity->revision boolean flag set, and so rather than adding the usage and returning, it skipped it and went on to delete the file.
A simple one line change to includes/entity.controller.inc fixed this for me. Here when saving a new revision, I set the $entity->revision flag, giving this bit of code in save():
Not sure if this was the correct place, but it has fixed the problem.
Updated patch attached.
Comment #128
Kristen Pol@stella An interdiff.txt would be handy :)
Comment #129
alanburke CreditAttribution: alanburke commented@Kristen
See http://drupal.org/node/996696#comment-6363272 last code block
Just one extra line added
Comment #130
Kristen PolAh... didn't catch that is was just that one line... sorry for the slowness ;)
Since it was not RTBC before this update, though, I guess I can't mark RTBC (although I want to!).
I'm not sure that #116 and #121 have been addressed (either that the patch will include this stuff or not and, if so, we need an updated patch).
Comment #131
indytechcook CreditAttribution: indytechcook commentedPer the comment in #121: state machine does not have the concept of default and neither should Drupal. You edit the revision you want to edit. The "active/current/live/whatever" is the one loaded without a revision and it should not matter where that is loaded form.
EDIT: This is allows you to have multiple draft revisions.
The terminology is wrong though and attached is the patch to fix it. I added a few helpers to the entity also. This works great with the bean patch. #1335494: Beans need revisions
Comment #133
indytechcook CreditAttribution: indytechcook commentedUpdated Tests.
This does change on assumption. It appeared as if the active check was different in loading then in saving which seemed a little silly to me. So I changed the "set active revision" to "active revision" in the entity info api key and just check that all the time.
Comment #134
indytechcook CreditAttribution: indytechcook commentedUpdating status
Comment #135
jstollerRe #131: Drupal and State Machine absolutely have the concept of a default revision. They just don't call it that, which is what #1643354: [Policy, No patch] Overhaul the entity revision terminology in UI text is trying to fix. Specifying this default revision is what the vid field in the node table is for. Drupal unfortunately screws this up by further assuming that the latest version should always be the default version, which every content moderation module jumps through hoops to work around. That is what #218755: Support revisions in different states is trying to fix. The concept of an active revision is a little less clear, but the safest default behavior when editing an entity would be to edit the latest version of that entity (assuming no specific vid has been requested), as that is currently the most active. This doesn't preclude having multiple draft revisions, but it is a more sane default than loading {node).vid.
Comment #136
indytechcook CreditAttribution: indytechcook commentedThanks for your comments jstoller. The definition you used for "active" implied a single draft revision assumption. Drupal or the Entity API module should not make this assumption IMO (also State Machine doesn't make any assumptions). This sounds like an implementation detail that should not be in an API module but in the implementing module itself.
I apologize for the discussion bickshed here. We really need to get this patch in. It's holding up a stable release and issues on other modules. Any other comments on the actual patch?
Comment #137
crimsondryad CreditAttribution: crimsondryad commentedI am all for getting the patch in as so many other modules rely on this, but I also see that if this module goes down the wrong path with terminology it may make fixing it later much harder as those other modules are going to rely on how this works. Case in point, the Entity API fix that was a workaround for a core bug last year that broke a bunch of modules when it got pulled back out.
Comment #138
jstollerI second @crimsondryad's concern. I would strongly recommend that this patch adopt the same terminology as #1643354: [Policy, No patch] Overhaul the entity revision terminology in UI text. That issue still has some debate over if and when the word "version" should be used instead of "revision", however there seems to be pretty wide-spread agreement on "default", "active" and "published" as standard terminology. Adopting that terminology here now could save much pain down the road.
Comment #139
fagoAgreed. Let's go with the default revision terminology here. I've worked over the patch and improved it quite a bit by fixed using the new terminology, having proper entity_revision_* API functions, simplifying test module code and baking in other improvements that went into d8 or are in the patch over at #1723892: Support for revisions for entity save and delete operations.
Updated patch attached.
Comment #140
fubhy CreditAttribution: fubhy commentedCan't actually test it right now but I read through the patch twice and couldn't find anything that bothered me. Looks much better now, too. Thanks...
Testbot says it is good so I think this is RTBC
Comment #141
cosmicdreams CreditAttribution: cosmicdreams commentedA documentation nitpick
This appears to be evidence of a comment that is too long. (over 80 characters)
Comment #142
fagoad #141: !? What's too long here? The marked lines don't exceed 80chars? Please be more specific.
Comment #143
fagoComment #144
fagoAs pointed out by stella in #127 we still have a problem with files, e.g. see what file_field_update() does:
I.e., it forces us to support $entity->revision.
$entity->is_new_revision
is much clearer to me though, so I'd prefer to have that in the API. Thus I've made $entity->revision to be a reference on $entity->is_new_revision.Patch attached.
Comment #145
fagoI've added a comments to the new entity_revision_* functions related to the "default_revision" flag, which clarifies it's only supported for entity api module entity types.
Comment #146
fagoPatch seems to work well, so I've committed it. Let's file any issues as follow-ups.
Thanks everyone! :-)
Comment #147
ygerasimov CreditAttribution: ygerasimov commentedcongratulations to everyone! :)
Comment #148
yannickooCongratulations!
Comment #149
HyperGlide CreditAttribution: HyperGlide commentednice work!
Comment #150
fagoTurned out
entity_revision_is_default()
is often needed generally, so I've committed a follow-up to make it work with all entity types.Comment #151
ktaiwo CreditAttribution: ktaiwo commented@fago et al
Hello,
I cant find where 'EntityAPIController::revisionTable' is instantiated in entity.controller.inc. My thought is that it would have been instantiated using properties from the hook_entityinfo i.e. 'revision table'. Thnx.
Comment #152
crimsondryad CreditAttribution: crimsondryad commentedAny idea on when the next release of the module will drop?
Comment #154
thedotwriter CreditAttribution: thedotwriter commentedAfter a quick look at the topic it seems that Entity API now support versioning (awesome!), so wouldn't it be a good time to update the home page of the module which still claim not to support it?
Comment #155
HyperGlide CreditAttribution: HyperGlide commentedagree.. perhaps when beta 5 or rc1 comes out.. seems the page was last updated when beta 4 was release in April.
Comment #156
crimsondryad CreditAttribution: crimsondryad commentedSeems there still isn't an official release that contains the patch. Hopefully soon?
Comment #157
steinmb CreditAttribution: steinmb commentedAlso I see not change record of this in http://drupal.org/list-changes/entity
Comment #158
Berdir@steinmb: You're welcome to create a change record, they don't write themself. Few contrib projects are currently using change records, and even if they do, not as strictly as core. It's a rather time-consuming task to write a good change record and it's hard enough to find people who write them for core, where it's enforced through the critical task threshold.
Comment #159
mradcliffeRe: #157, #158: I have started a documentation page about revisions at http://drupal.org/node/1892478.
I'm looking at this from the angle of custom entities that did their own revisions before and the steps to use the new revision system. It is incomplete and probably worded inaccurately.
Comment #160
sarjeet.singh CreditAttribution: sarjeet.singh commentedSubscribing
Comment #161
joeebel CreditAttribution: joeebel commentedSubscribing
Comment #162
jstollerThere is no need to post to an issue in order to subscribe to it anymore. Just click the "Follow" button at the top of the page. See Stop subscribing, start following for more information.
Comment #163
sarjeet.singh CreditAttribution: sarjeet.singh commentedThanks @jstoller.