Problem/Motivation
In Drupal 8 and 9, some weird behaviour happens in Views Time-based cache.
The problem only occurs when using Time-based "Custom" time.
Problem 1:
Configuration results_lifespan and output_lifespan are never saved as 'custom'.
It is saved as 0, even if we choose 'Custom'.
Problem 2: (php8 only)
in getLifespan, we have this one liner
$lifespan = $this->options[$type . '_lifespan'] == 'custom' ? $this->options[$type . '_lifespan_custom'] : $this->options[$type . '_lifespan'];
Since $this->options[$type . '_lifespan'] is never 'custom' but 0 instead (problem 1),
it is like:
0 == 'custom'
Now in php7, this returns TRUE.
But in php8, this returns FALSE, so when views_ui loads the views, custom time-based cache will always show '0sec, 0sec'.
Why this happens
When building options (buildOptionsForm), there is some formatted [60, 300, 1800, 3600, 21600, 518400] options as $options
and then
$options = [0 => $this->t('Never cache')] + $options + ['custom' => $this->t('Custom')];
But views.cache.schema.yml type for both results_lifespan and output_lifespan is integer
Steps to reproduce
Edit a view
Set Caching as Time-based with Custom value
Save the view
Check Caching value again
Proposed resolution
Remove the _custom storage fields - the view config always should store the raw value in a single field.
The UI still offers a dropdown with a "custom" option, but stores the value in the single field, and recreates the custom option on reload if required.
Remaining tasks
Reviews and input from community.
| Comment | File | Size | Author |
|---|---|---|---|
| #43 | 3233105-43.patch | 5.84 KB | mrinalini9 |
| #31 | 3233105-28.patch | 5.84 KB | smustgrave |
| #28 | 3233105-28-tests-only.patch | 2.9 KB | smustgrave |
| #28 | interdiff-12-28.txt | 2.53 KB | smustgrave |
| #25 | 3233105-25.patch | 6.74 KB | simgui8 |
Issue fork drupal-3233105
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
simgui8 commentedHere is a patch for the proposed solution.
Comment #3
longwave-1 seems a better choice than 7 to mean "custom".
However, isn't this really only a UI issue? Why do we need both
results_lifespanandresults_lifespan_custom? We could store only one value, and then display the custom setting if the value isn't in the list of dropdown options, we don't need to store both.Comment #4
longwaveThis seems related to, or perhaps a duplicate of, #3024941: The error in output select options in page "Caching options" after saving view
Comment #5
simgui8 commentedThanks longwave,
For the related issue 3024941, I missed it even if I did search a lot for similar issues.
3024941 assume that
results_lifespan_customgets emptied when passing from Custom time-based caching to another time-based options.This is not the case, it is only updated every time 'custom' is chosen.
We need both
results_lifespanandresults_lifespan_customby design.results_lifespanstores Never-cache + some predefined options and customresults_lifespan_customonly stores custom int valuesIt is a UI issue only with php7.
It is broken and non-functional with php8, because getLifespan gets called very often.
To replicate with php8:
Set N seconds custom value on a view with random sort.
Navigate to the view with a non anonymous user
and reload the page every N seconds
Nothing happens (problem #2)
Switch back to php7:
The views get updated every N seconds.
Comment #6
longwaveWhy can't
results_lifespanalways store 0 for never cache, or the exact number of seconds? Then the UI can show the dropdown and hide or show the custom field depending on if the stored value is in the dropdown or not? This would simplify the logic of using the value at least.There is nothing at present stopping you from saving a value that's not in the dropdown for
results_lifespan, and it will work (except in the UI). There is also no difference between results_lifespan = 600 and results_lifespan = custom, results_lifespan_custom = 600.Comment #7
simgui8 commentedOk sounds great.
I will test this and upload a new patch.
Comment #8
simgui8 commentedAfter reviewing what's there now, the most straightforward and less intrusive fix would be to use a specific integer for custom option, let say -1.
That way we can easily keep "legacy" UI options at one place in
buildOptionsForm.There is also the option to remove legacy options, and only use Never cache or Custom. Then I guess
results_lifespan_customandoutput_lifespan_customwould become obsolete.Another path could be to create a method to return legacy options, and rely on that in:
buildOptionsForm(show/hide)validateOptionsFormgetLifespanAnyhow, here is the 1st option patch.
Comment #9
simgui8 commentedComment #11
joachim commentedLGTM, just one small suggestion:
Could we make this -1 value a class constant for better DX? e.g. static::LIFESPAN_CUSTOM
Comment #12
simgui8 commentedHere is an updated patch.
@joachim, let me know if it looks good to you so I can integrate your better DX suggestion into my dev routine :)
Comment #13
simgui8 commentedComment #15
lendudeThis issue came up as a triage issue in #bugsmash
Nice work on this. #12 does look like the less invasive approach, but I think I like the proposed #6 more, getting rid of any setting sounds good to me, we have too many in Views anyway. It also feels like it would indeed simplify the logic a little.
Anyway, this needs test coverage and if we go for #6 it would need an upgrade path to get rid of the old settings.
Comment #16
simgui8 commentedI agree with dropping settings.
So this would mean removing
results_lifespan_customandoutput_lifespan_customand adjusting core/modules/views/src/Plugin/views/display/DisplayPluginBase.php accordingly ?
+ test coverage
Comment #20
smustgrave commentedClosed https://www.drupal.org/project/drupal/issues/3024941 as duplicate of this
Moving over credit for
asya_asina = initial patch
Aanal.addweb = first testing
Amber Himes Matz = triaging and discovering the duplicate
Comment #21
smustgrave commentedMoving to NW for the tests
Verified the issue exists in 9.5
Verified the patch in #12 still applies and fixes the issue.
Not sure if some kind of notice will be needed since site admins will have to go in and fix their views if currently using that setting.
Comment #22
simgui8 commentedHere is another shot a it,
completely different approach (more like #6).
Comment #23
longwavePHPCS failed:
Comment #24
smustgrave commentedAlso will still need tests.
Comment #25
simgui8 commentedThis one should pass phpcs
Comment #26
smustgrave commentedSo the current question is the approach in #25 better than #12.
Adding Needs subsystem maintainer review to get their review on this as I don't have much an opinion on either approach.
Comment #27
smustgrave commentedSo after testing it seems #12 is the more complete solution.
#25 when I exported my view it didn't show that I had a custom setting. It exported the seconds but if those seconds were say 3600 the view would load that as non custom.
Comment #28
smustgrave commentedAdding a test
Comment #29
simgui8 commentedThanks for the test! I will have a run at it and report back.
As for #27
If we remove
results_lifespan_customandoutput_lifespan_customconfigurations, we have to show/hide the custom seconds form element based onresults_lifespanandoutput_lifespanSo if we put any of the defaults options as "custom", we can't trigger show/hide
$options = [60, 300, 1800, 3600, 21600, 518400];If we want to fix this issue, #12/#28 should do the work.
If we want to remove some settings for time based cache,
#25 is a try, but it might be better to open another issue with a detailed shopping list.
Comment #31
smustgrave commentedHere's the patch I meant to upload. Just uppercase C
Comment #32
simgui8 commentedThe updated patch with uppercase C pass tests on my side (#31).
Thanks
Comment #33
simgui8 commentedComment #34
longwaveI have run into this again on a project, #31 works for me and is the simplest way to fix this; we can improve this later in followup issues.
Note that usually this sort of change would require an upgrade path but currently this feature is broken and views are not saved correctly when the custom option is used, so I don't think an upgrade is viable or useful here.
Comment #36
alexpottI think given this is quite broken we should consider how this works. I think saving both results_lifespan_custom and results_lifespan (and the duplicate for output_lifespan*) is really odd. We should be saving on lifespan.
The logic could be something like this. If the lifespan is not in the preset list then set it to the custom lifespan option and set the default value of the test field. On save if the lifespan is set to custom then replace it with the integer from the custom lifespan field. That way the final view has less fields and makes more sense.
Comment #37
alexpottSorry looked at the patch directly... didn't read #35. Sorry @longwave. As per #36 I think that considering this is totally broken we should take the opportunity to fix it in the best way possible rather than do it in steps because it's not as if it is partially working.
Comment #39
fgmSimilar bug with more details and different explanations at #3371265: Views time-based caching stores and custom duration as zero, marking as duplicate since this one already has a patch in the works.
Comment #40
crutch commentedPatch isn't applying to 10.1.8. Needing 24 hours.
$options = [60, 300, 1800, 3600, 21600, 86400, 518400];Comment #41
simgui8 commentedComment #43
mrinalini9 commentedHi,
Rerolled patch #31 for 11.x branch, please review it.
Thanks!
Comment #44
smustgrave commentedComment #46
mrinalini9 commentedCreated MR for the changes in patch #44, please review.
Comment #47
smustgrave commentedPipeline has issues.
Would recommend checking that everything is green before putting into review.
Comment #48
mrinalini9 commentedFixed pipeline issues and updated MR, please review it.
Thanks!
Comment #49
longwaveThis still uses two separate config keys, which isn't necessary - to make the config simpler we should implement @alexpott's suggestion from #36.
Comment #52
herved commentedCross-referencing #3609866: Views Time cache "Never cache" label is misleading and caches permanently which could impact this issue.
Comment #54
longwaveImplemented #36 with help from Claude Code. The
_customfields are gone, there are now justresults_lifespanandoutput_lifespankeys that store the raw value, the UI handles the selection of preset vs custom values.The update hook removes
_customfields and preserves existing behaviour: only if the raw value is the string "custom" then the custom value is actually used.Comment #55
smustgrave commentedSorry can we clean up the summary some? Solution says option7?
Comment #56
longwaveUpdated IS.
Comment #57
marcoscanoI have reviewed the MR and tested manually. Didn't find anything major IMO, so I think we should be close to ready here.
Setting as NW just to update the CR URL in the MR, then to me this is ready for RTBC