Needs work
Project:
Drupal core
Version:
main
Component:
forms system
Priority:
Major
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
28 Jan 2014 at 06:06 UTC
Updated:
18 Jun 2020 at 01:01 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
effulgentsia commentedComment #3
effulgentsia commented#2 will likely pass, but only due to missing test coverage. This adds a test to ensure the $form_state survives even when $form cache is cleared. This test is expected to fail, because FormBuilder still couples the two. Next step is to decouple that.
Comment #5
effulgentsia commentedComment #6
effulgentsia commentedComment #7
berdirI don't really see how this could work? Try this:
1. Apply patch, rebuild.php
2. Visit node/add/article
3. Empty cache_form
4. Try to upload an image.
=> An unrecoverable error occurred. Use of this form has expired. Try reloading the page and submitting again.
Comment #8
sunLike @Berdir, I'm not able to follow this proposal either.
The form + form_state cache items are very tightly tied to each other.
We purposively moved cache_form outside of the cache system: #512026: Move $form_state storage from cache to new state/key-value system
And some closely related, long-standing bug reports:
#1694574: drupal_process_form() deletes cached form + form_state despite still needed for later POSTs with enabled page caching
#343415: Form cache is not cleared on submit when page cache is activated
Comment #9
effulgentsia commentedNope. That issue purposely moved $form_state to kv. $form went with it, not by design, but because of:
That's what I'm working on untying. CNRs on this issue so far are for bot. When it's ready for human review, I'll unassign myself from this issue, and create a real issue summary. Feedback in the meantime is welcome, just realize it's a work in progress.
Re #7, yep, aware of it, and working on that.
Comment #10
effulgentsia commentedThis addresses #7, but is still raw.
Comment #12
effulgentsia commentedComment #14
effulgentsia commentedComment #15
effulgentsia commentedThis fixes the easy fails. FileField, Views, and Batch need more investigation.
I also updated the summary to explain what the patch does, but not yet why. Though maybe for some of the followers of this issue, it's obvious?
I'll post interdiffs from here on out, so if anyone wants to start a architecture or code review, despite a few test failures still, go ahead. I don't think I'll have much time to work on this for the next 2 weeks, so unassigning myself for now, but I'll post new patches with interdiffs if/when I can get to it.
Comment #17
effulgentsia commentedNew thought based on #2208115-15: Add DependencySerializationTrait. What if we stop caching/persisting $form entirely? Once the remaining failures here are resolved, it becomes completely unnecessary. The cache hit ratio on $form is at best 50%, and it's not that expensive to rebuild from $form_state: if computationally/io expensive information is needed (e.g., from a web service call to another site), then that can be stored in $form_state.
Meanwhile, completely removing $form from being serialized gets us out of the dependency serialization craziness we currently do.
Comment #18
joelpittetThat sounds very sane. I'd really like that!
Comment #19
sunThat sounds interesting, but frankly, it's a radical change proposal that at least I have to swallow and sleep over first.
I'm not really sure whether the premise of "fast to compute" is really true for the forms that actually need form caching — most forms just inherit it due to #ajax, and speaking of, #ajax might be one of the exact points where the idea breaks down, because #ajax changes the cached
$formstructure.Comment #20
effulgentsia commentedOf course. I'd like you to keep an open mind at least until the patch is green, so concerns about "it can't possibly work" are removed. But feedback before then is welcome too.
It does, but it should only do so based on a corresponding change to $form_state, so that the new $form could be rebuilt from the new $form_state if needed. There may be some ajax forms that don't do this (including possibly the ones causing the remaining failures), but I consider that to be a bug. If you have experience from Mollom or other contrib projects that provide a solid use case for changing $form in a way not possible to rebuild from $form_state, please share those.
Comment #21
catchCross-linking #2263569: Bypass form caching by default for forms using #ajax., I haven't caught up with this issue yet but it'd definitely impact that one way or the other.
Comment #22
tim.plunkettNow that we have Drupal\Core\Form\FormCache, and $form_state is no longer an array, this could use an issue summary update
Comment #23
chx commentedFormCache is using
$this->keyValueExpirableFactory->get('form')which is great because the form cache never was a cache to boot. This I conclude done.Comment #24
effulgentsia commentedI opened this issue in order to make it into a true and proper cache, and only putting state information into $form_state and not into $form. I haven't had time to continue this further, but I'd still like to, whether for 8.0 or 8.1. I'm hesitant to postpone it to 8.1 prematurely though, because there are known performance problems from $form storage growing out of control, even with relatively short expiration. Being able to apply a proper cache backend for it (including a NULL one) while still having ajax and multistep forms function properly would be a big win for that. Raising to Major for that.
Comment #25
joelpittet@effulgentsia has this happened, it doesn't look like 'cache_form' is a bin in D8, maybe it got renamed or something? Has this become moot is there anything salvageable from this?
Comment #26
effulgentsia commentedPostponing this on #2502785: Remove support for $form_state->setCached() for GET requests. After that, I'll see if there's anything left here worth doing. I still think it would be good in theory to only persist $form_state (and not $form) for multistep forms and state changes that result from validation errors, but I don't know if doing so would bring big enough benefits to bother. The main benefit would be to reduce the storage needs of the kv, especially for large $form's, but with #2502785: Remove support for $form_state->setCached() for GET requests reducing persistence to only POST requests, that benefit isn't as large as when I first opened this issue.
Comment #27
joelpittet@effulgentsia one concern I'm facing in D7 commerce is form state on cart pages is huge when form state persists the form args and the second arg in a views form is the entire view object. The results tends to load the entire node on a results field called _field_data.
Also it is always multi step.
There is a patch to help form but not form_state with this.
And this drags down cache insert with a large blob as well as to a lesser extent unserialize/serialize.
There is an interesting comment around why form cache is needed in views, I'll see if I can dig it up but to to the extent that the "rows may change and thus the form between requests"
Any ideas where we can reduce/remove that need? Glad to open a follow up if there is a way forward on that.
Comment #30
hchonovReading through the issue I am not sure that not caching the form is necessary a good idea.
When using Ajax / multi step forms the main use of the cached form is when the user input is submitted and the form is validated and in this first step the form will be retrieved from the cache instead of rebuilding it.
The second step almost always flags in the Ajax submit the form for a rebuild. As a summary : having form cache means that on Ajax the form is retrieved once from cache and then rebuild and without form caching the form will be rebuild twice on Ajax. Having really big nested entity forms rebuilding the form might be expensive and it would be better doing this only once instead twice. I've measured the performance of FormBuilder::doBuildForm and it currently takes up to 2 seconds for our biggest forms, which means without form caching this will be 2x2 seconds.
Comment #31
hchonovAnd also if the validation fails having rebuild the form would've been unnecessary as the previous cached form is being returned to the page but with errors set on the form elements which couldn't pass the validation.
Comment #35
fgmFWIW, this issue is related to a bug in the KeyValueExpirable storage code and/or documentation: #2769955: KeyValueExpirableFactory incorrectly chooses its storage.
Comment #37
geek-merlinImho better approach:
In #2263569-61: Bypass form caching by default for forms using #ajax., an imho better approach was sketched:
Comment #39
tim.plunkettBlocking issue was committed (2 weeks after it was made blocking, in July 2015)
Comment #41
andypost