Closed (fixed)
Project:
Autosave Form
Version:
8.x-1.x-dev
Component:
Entity form autosave
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
16 Nov 2017 at 12:01 UTC
Updated:
13 Nov 2023 at 10:49 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
hchonovWe could not offer any autosave for content that doesn't exist. So you have first to create and save the content and afterwards during editing it autosave states will be created. Does this answer your question?
Comment #3
ptmkenny commentedI had the same question when I installed this module today.
I now understand that the entity has to be created first before autosave will work.
So, is there an easy way to give the user a link to "create a node" that automatically creates a node and then redirects the user to the edit page (instead of going to node/add/contenttype, where autosave doesn't work)?
Comment #4
hchonovNo, this is not something that belongs in the autosave module.
When I initially implemented the module, I was thinking that we need an entity ID and when the entity is not yet saved there is no entity ID. But I think that in such cases we could use as an entity ID just 0 which will identity new entities. Do you wann give it a try with a patch and I could take a look at it?
Comment #5
ptmkenny commented@hchonov I agree that the "automatic node creation/redirect to edit page" is out of scope for this module, but I was wondering if there was a guide for doing this somewhere. If not, I will try to figure it out and then write up instructions, which perhaps could be included as a code example in the module's README file.
I think it's better to only allow autosave on created entities (entities with an ID), because using an EID of 0 may be dangerous since many users may each go to the /node/add/contenttype page for multiple content types, and it seems like having a bunch of content with no EID could lead to a security issue. So instead, I want to find a way to save the entity and then edit it on creation.
Comment #6
ptmkenny commentedWorking on a solution here: https://drupal.stackexchange.com/questions/251788/link-to-create-a-node-...
Comment #7
MaskOta commentedWill need work but it seems to do the job.
I need help in "autosave_form_form_alter" with the proper route detection.
Comment #8
hchonovThank you. This looks promising :).
Looks like copy paste of autosave_form_entity_update. It would be better to provide a helper method and call it from the the insert and update hook.
We should use here 0 as well for the entity ID, but better would be to call a method returning the entity ID to use.
A better documentation is needed :).
The method name could be simply getEntityId().
This could be changed to return $entity->isNew() ? 0 : $entity->id().
As we do it at multiple places we need a method for retrieving the entity ID from everywhere. We could make the method defined in the AutosaveEntityFormHandler as public static and use it here.
Comment #9
hchonovThe comment above states why we restrict the autosave only to routes which are defined through _entity_form. If we check for _controller on the route we don't now if this is the form being retrieved by that controller. I guess that what is causing problems here is the node add route? Then probably you should open an issue in core to exchange the controller through an _entity_form definition in the options :).
Comment #10
MaskOta commentedThanks for reviewing. I also found that i missed an "isNew()" check in the "storeEntityAndFormState".
I apologize for the lack of interdiff. I screwed something up with branches and commits :) I think i figured it out now.
Comment #11
MaskOta commentedre-rolled patch against latest dev
Comment #12
aguilarm commentedWould it be reasonable to adjust the
autosave_form_entity_formtable to save an entity uuid rather than the entity id?If that was switched, the
node/add/{bundle}handler could redirect tonode/add/{bundle}/{uuid}, autosave_form could start autosaving this new, unique, item and the node add form could use this new uuid when creating a node if it exists in the route.Items in
autosave_form_entity_formcould be cleaned up on cron if no entity exists to match the uuid.I think using 0 like this means users will only be able to work on one unique unsaved node, so if they open node/add several times and work on many separate items they'll be sort of randomly overwriting the autosave data, no?
In the meantime I may be using the 'redirect node/add to node/edit on a new node' to have autosave always active, but cleaning up blank nodes is a bit problematic there.
Comment #13
aguilarm commentedHad a go at adjusting your patch @MaskOta and rather than using 0 for the id, using the uuid if it exists.
I think the uuid will always exist? New nodes are created but not saved and they generate a uuid so that's good. I'm not certain of entities that do not use uuids but if there are none we can ditch ids all-together, yeah? This patch just adds length to the id field to acommodate uuids or ids. Probably should make a new uuid field or switch id to uuid.
I added a route override for node/add/{type} that goes to node/add/{type}/{uuid}. Might be unnecessary but will allow users to get back to their in progress node from browser history. I think without that it's not useful?
I've only tried making nodes so I might be missing something for other entities like config.
Thanks!
Comment #14
Anonymous (not verified) commentedpatch #11 works for me after re-roll
Comment #15
Anonymous (not verified) commentedComment #16
davidburnsLatest patch works well.
Comment #17
hchonovRe #12:
It would be nice to create a dedicated issues for such questions. But still an answer - no, I don't think that it makes any sense to use the uuid instead the entity ID. First of all the autosave states are local and shared among environments. And also this would make the current issue impossible to solve, because new entities always have a different uuid.
Why adding such a complexity when we already have the entity hooks taking care of this?
There is an issue to prevent 2 autosave sessions - #3038789: Prevent overwriting fields with second browser tab/window.
This is not a good idea, because the forms on the add and edit pages might be different as well as the form alter hooks might be manipulating the form only for one of them.
In general I don't really see any advantage of using UUIDs instead of IDs. However if you still feel like this might be useful, then please open a new issue and let's continue the discussion there.
Comment #18
hchonovRe #9:
Unfortunately we cannot have that change. See the consequences of it in #3083756: Undefined index and Undefined offset $route_defaults['_entity_form'].
Re #10:
There is still very big overlap between hook_entity_update and hook_entity_insert with the only difference that in the latter we consider the current user. This all could be put in a helper method having an optional user parameter, which is invoked by both hook implementations.
No, 0 should be passed to the helper function only from within the insert hook.
Unfortunately not. I'll comment on that again in a next comment.
Comment #19
yesct commentedI tried taking out the two references to
$route_defaults['_controller']mentioned in #9 and that were causing the conditions to allow the code to get to$route_defaults['_entity_form']even if that was not set, causing the errors:Notice: Undefined offset: 1 in autosave_form_form_alter() (line 78 of /app/web/modules/contrib/autosave_form/autosave_form.module) #0 /app/web/core/includesNotice: Undefined index: _entity_form in autosave_form_form_alter() (line 78it did stop the errors from showing in the recent error log .... but also, when I revisited an existing node edit page that had been locked and autosaving, when answering to resume editing, the changes I had made were not preserved.
(Note I did not try on node add.)
So I agree this still needs work.
Comment #20
yesct commentedThere was enough difference that the automatic patch apply could not apply the patch, re applied manually, and it did apply with a lot of offsets. Here is just that reroll with no changes.
(setting to needs review, just to see if the d.o test bot can apply it)
Comment #22
yesct commentedoops. the patch command left .orig files. sorry. here it is without that cruft.
Comment #23
yesct commentedand here is the change I tried to see if it might still work without the _controller in the ifs.
Comment #25
hchonovCrosspost, a review based on the previous patch.
As already written in the previous comment this change causes problems.
It was introduced because of how the node add route is defined:
However this could be changed in core and let core define the route through
_entity_forminstead. See also the recommendation inentity.api.phpfrom theEntity routessection:The problem with relying on _controller is that we have to ensure that there is only a single entity form shown. I haven't yet thought about how we could do this, but as soon as this is against the recommendation of defining entity form routes, I don't think that it is worth it considering this and introducing such complexity at all. Instead we should open a core issue for switching from
_controllerto_entity_formfor thenode.addroute. I've created an issue and provided a patch for that - #3084030: route node.add should be defined through _entity_form instead through _controller. It would be nice if someone could review it.While I was thinking about how to unify both the insert and the update functions, I've realized that the insert function only needs this lines and all the others are unnecessary. The reason is that we when we insert an entity we don't care whether conflict is enabled or not and we simply want to delete the autosave states for the current autosave session. Also we should not retrieve the ID for that through
$entity->id(), as the newly saved entity will already have a real ID assigned, but for the autosave states we used as identifier0.Let's put the extended documentation as a note. I suggest the following method documentation:
Needs type hint and documentation.
Missing new line between the parameter and return declarations. The return type should be
"The entity ID to use for the autosave storage."
As the autosave handler might be exchanged we need to retrieve the class from the entity type instead of using the default class.
I've also just realized, that we have one drawback of having the
getEntityIdmethod checking for the entity being new - we cannot use it in the insert hook, as the entity isn't new anymore. Having a method and hardcoding 0 at other places is not really acceptable. We need to come up with a solution, which we might use everywhere.Re #23:
@YesCT, the change is okay for autosave (we just need to still completely revert it and remove the surrounding brackets). However node.add will not work anymore. I've created an issue and provided a patch for that - #3084030: route node.add should be defined through _entity_form instead through _controller. It would be nice if someone could review it.
Comment #26
hchonovLet's make it configurable per setting whether Autosave should be allowed for new entities and check for that setting in
AutosaveEntityFormHandlerInterface::isAutosaveEnabled().I am not yet sure whether the feature should be enabled or disabled by default. Any thoughts on that?
Comment #27
hchonovThe referenced issue was committed to Drupal 8.8.x, which means that there is no need for the _controller change here in order for autosave to work on node creation. Yay!
Comment #28
chr.fritschThen we have to decide if "autosave on node creation" is only supported in 8.8.x, or do we want to build some fallback for 8.7?
Comment #29
hchonovEither we try to convince a committer to commit the issue or part of it to 8.7 as well or we include here a fallback and allow the node.add route.
Comment #30
tomefa commentedHi everybody, first thank you for this module ! it is a really good feature for contributor.
Also i wanted to use the module with the version 8.x-1.0 and not the dev branch.
And the drupal core is 8.7.
The patch from #23 wasn't working, but i added the "if" on the controller :
"if ($route && ($route_defaults = $route->getDefaults()) && (isset($route_defaults['_entity_form']) || isset($route_defaults['_controller']))) {"
Then it was working but with 2 warning on $route_defaults and $entity_type_id, so i add a check on them and now it is working for drupal 8.7 and autosave_form 8.x-1.0.
Here is the patch for the people who needed it.
Comment #31
petu commentedThe patch #30 works fine for me. Thanks!
Comment #32
geaseAnswering comments from #25.
#1 Since node add uses an entity form route, we are fine. Just removed extra brackets.
#2 Rewritten insert hook, please check. Do we need checks for entity autosave_form handler? How it is possible that there isn't one if we define default in hook_entity_info_alter?
#3,4,5 Updated documentation and code style
#6 Used the handler with the checks if it exists, which (see #2) I'm not sure are necessary.
#7 I don't have a good idea how to solve this. Bad ideas are setting some flag on entity in insert hook, that might change the outcome of getEntityId() method, or using another hook, eg, presave.
Comment #33
hchonovIf it was unset explicitly in a following hook implementation.
It will be easier to understand and read if we simply skip the whole processing if there is no autosave_form handler. Lets add a constant and document ::getEntityId() that it will be returning either the entity ID for existing entities or that constant for new entities. Then we can safely use the constant as we've made a contract on the method what it will be returning.
But what if the method was overridden and wasn't returning 0 for new entities? We need to use the same logic everywhere.
Comment #34
geaseHere I'm introducing a config parameter asked for in #26
Though I didn't understand this
Did you mean that this method should check just one config setting? Its name implies the opposite, that the whole check we make in hook_alter_form should be moved there. In both cases, I see a separate method as an overkill. To check for one config setting, it definitely is. To move all the logic defining if form should be altered - again, we use this logic just once, and check for the new setting separately in hook_entity_insert.
I have still rearranged code in hook_form_alter to make it more clear and eliminate duplicate actions or mere mismatches (eg, $entity_type_id variable was used to designate totally different things in different chunks of code - either the actual form entity type or the entity type expected by the router).
What bothers me is that we use hook_entity_update and hook_entity_insert which don't know about submitted form, was it autosave form or not and the entity of the form. And we try to use indirect logic to guess what entity was updated/created, and we have problems there. Cannot we move the logic from update and insert to form submit?
Then, about the route detection. Quite imaginary situation, but still, am I missing something or not: page which is routed to some entity add form, but which has blocks that contain other entity of the same type add forms. Will the detection work correctly?
And last: failing test actually should fail, because it makes sure there is no autosave js on create form. Well, with this update it should pass because I set the default of new config variable to false, but in general, we would need some test for this patch.
Comment #35
kalabro#34 worked well for me, thanks very much @gease @hchonov. Anything I can help with in this issue to push it forward?
Comment #36
wells#34 also working well for a site where we have deployed it. In our case with a pretty complex node type (many fields and lots of entity references, media, etc.). I'm not sure if @gease's comments in #34 hold anything back here, so marking RTBC for now.
Comment #37
tomefa commentedThe new function "autosave_form_entity_insert" generate a delete query for every entity save on the system.
It would be better to limit it to the entity select in the admin config form of autosave.
That would reduce a lot the not necessary delete query.
Comment #38
tomefa commentedComment #39
amateescu commentedReroll and a small fix.
Comment #40
wellsMarking Needs Review. The updated patch in #39 at least adjusts the update hook name to prevent a collision with the latest version of the module.
Comment #41
s_leu commentedI didn't do a full review of the code/functionality but just noticed this:
$entity isn't used anymore after this change, so the line above the changed one be dropped.
Comment #44
wranvaud commentedCode from #39 updated and tested. Ready for review.
Comment #45
jan-e commentedFor easier reviewing I created 2924006-44.patch from the merge request !8 and did an interdiff between #39 and #44.
Comment #46
wolcen commentedPatch 39 working here for new items. (Have not fully reviewed source).
Comment #47
phernand42 commentedTested patch in #45 and it applied cleanly and worked fine on the current version of the module (8.x-1.4). However, after I removed the patch, the "saving draft" notification keeps appearing right away whenever I edit a page. The current time interval I have setup to trigger autosave is 20000 milliseconds. So I shouldn't see the "saving draft" notification right when I edit a page. I doubled checked module code to make sure none of the patch code was still present and it wasn't. Not entirely sure if this is related to patch or not but I thought I should share.
Comment #48
hchonovThis should fix the failing test as now it is expected that the library is loaded on new entity forms.
Comment #49
staalex commentedTests are trying to use 'classy' which no longer exists in D10. Let's try with 'starterkit_theme'.
Comment #51
hchonov