Updated: Comment #42
Problem/Motivation
This bug is known to affect files, checkboxes, dates, boolean and probably other fields. Multistep forms are especially affected because any files (or field settings) added in previous steps will be lost when the form is finally submitted on the final step. This is because fields which are not in the active step are hidden with #access=false.
Steps to reproduce
1. Create a new content type with an image field and give it a default image.
2. Add a node of that content and upload an image different from the default.
3. Create a new module and in the .module file, add the following code (note, this module is named `devmodule`):
<?php
function devmodule_menu() {
$items['devmodule'] = array(
'page callback' => 'devmodule_callback',
'access callback' => TRUE,
);
return $items;
}
function devmodule_callback() {
module_load_include('inc', 'node', 'node.pages');
$node = node_load(1); // Use the nid of the node you created in Step #2.
$form = node_page_edit($node);
$form['field_image']['#access'] = FALSE; // 'field_image' is the name of the image field added in Step #1.
return render($form);
}
4. Enable the module and clear the cache.
5. Navigate to the menu path defined in the module (i.e. http://d8.local/devmodule) where you should see the node edit form without the image field.
7. Save the form.
8. Result: The image file is deleted and replaced by the default image.
Proposed resolution
The following code exists in file.module:
// Process any input and save new uploads.
if ($input !== FALSE) {
$return = $input;
// Uploads take priority over all other values.
if ($file = file_managed_file_save_upload($element)) {
$fid = $file->fid;
If file is #access=false, we have $input = NULL (which is !== false), thus, $fid is set to 0.
Changing
if ($input !== FALSE) {
to
if ($input !== FALSE && $input !== NULL) {
fixes the issue. No side effects were confirmed so far.
Remaining tasks
Determine if the test is adding new test coverage, if so add it.
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #83 | interdiff_81-83.txt | 1.27 KB | pooja saraah |
| #83 | 1205822-83.patch | 3.14 KB | pooja saraah |
| #81 | 1205822-81.patch | 3.05 KB | quietone |
| #67 | file_s_silently-1205822-67.patch | 3.08 KB | deepakaryan1988 |
| #56 | interdiff-53-56.txt | 3.88 KB | babruix |
Comments
Comment #1
webchickComment #2
xjmTagging issues not yet using summary template.
Comment #3
geek-merlinComment #4
Gman commentedI too was using the multistep module and noticed my images disappearing when saving other steps which did not include the images. When investigating this issue, I came across this patch.
I can report that the submitted patch resolves the issue (no files/images silently deleted from the node).
I would suggest changing the title to "File(s) silently deleted when #access=false" as that more generally represents the issue at hand.
Comment #5
xjmAnyone can change the title. :)
Comment #6
geek-merlinso rtbc as of #4
Comment #7
webchickLet's get some test coverage on this. Looks like extending file_module_test_form() in modules/file/tests/file_module_test.module to include an $access parameter might be a place to look.
Comment #8
stefan freudenberg commentedComment #9
catchTagging for backport.
Comment #10
Yuri commentedI tested this patch on D7.12 with the current Multistep dev 2011-June-27, and confirm that files stay saved in multiple steps. As far as I experience now there are no side effects.
Comment #11
geek-merlinso this patch still works unchanged for d7 and d8 as reported in the OP and is rtbc.
we still need test coverage as pointed out in #7
Comment #12
webchickStill needs test coverage != RTBC. :)
Comment #13
xjmIt's not RTBC until it includes those tests. :)
Edit: Crosspost. :P
Comment #14
geek-merlinups sorry i meant to revert that myself.
Comment #15
stefan freudenberg commentedHi. Sorry for failing to report back. I am having trouble making my test fail without the patch D7. Can you share your form axel.rutz?
Comment #16
star-szrI'm trying to put together a test case for this, from my understanding we need to use a multi-step form to test whether the patch fixes the bug, my approach so far has been to add another button to the
file_module_test_form()form. I've attached my work-in-progress file_module_test.module patch, I know it's not pretty. So far I've just been testing file_module_test.module directly in the browser by removinghidden = TRUEfrom file_module_test.info.Here is my testing procedure, after enabling the 'File test' module:
file/testfile_managedtable.With this test case, the patch doesn't seem to make a difference, so I think I'm definitely missing something.
Comment #17
xjmMaybe we could try creating a form with the multistep module, with which the patch reportedly solves the issue, and inspect that form's structure?
Comment #18
stefan freudenberg commentedWe have to simulate the way it does multistep. It's not a core module, so we cannot use it here. Every step in multistep form module is actually a different URL.
Comment #19
webchickSince this is showing up only in a contributed module and so far not replicable by core, degrading to normal.
It would be nice if the maintainers of said module could handle creating the test case. Core developers have so far been unsuccessful in creating it by sticking to common patterns in core, so I'm guessing multistep is doing something a bit out of the ordinary.
Comment #20
star-szrFrom what I saw when testing the Multistep module, the module seems to alter existing forms (it doesn't create forms of its own), and stores the step in the URL query string.
As the original issue stated, the Multistep module sets #access = FALSE for fields not on the current page. The fact that this is done through a field_group.module hook -
hook_field_group_pre_render()complicates the issue even further, and makes it harder to reproduce this behavior in a comprehensible test case in core.It was also pointed out when discussing this issue on IRC that the existing condition (below) was likely written that way for a reason, so we definitely need tests (and comments in the code) to prove that this change is sound.
if ($input !== FALSE) {Comment #21
martijn houtman commentedI bumped into this problem while creating a block (in a custom module) that grabs the user_profile_form, which contains an image-field and setting this field's #access to FALSE: after submit the previously-set image is deleted.
So I just wanted to state that this does not _just_ happen when using the Multistep module, it happens whenever you set a file-field or image-field to #access FALSE. The test-case would most likely be easier to follow my steps.
And now save the form. In the current situation, the image will be deleted.
I can confirm changing ($input !== FALSE) to just ($input) fixes the problem, while maintaining the ability to unset a file with the 'remove' button, so I think this fix is correct.
Comment #22
mrharolda commentedIt seems checkboxes have the same issue...
Comment #23
martijn houtman commentedThe fix (removing !== FALSE) does have a side-effect: with an image field that has a default image selected, the fix prevent you from unsetting the default image. Going to look for a better fix ...
Comment #24
ACF commentedComment #25
yesct commentedNo work for a few weeks. Making it unassigned so it can be picked up by anyone. ACF, reassign it back if you want, no worries. :)
Comment #26
dags commentedComment #26.0
dags commentedtypo
Comment #27
dags commentedI moved this comment into the issue summary.
Comment #28
dags commentedI did some investigating and found this snippet under file_managed_file_submit($form, &$form_state) around line 1259 in file.module.
Removing the if statement around file_delete() solves the problem with the default images not being removed. But that doesn't seem like a reasonable solution.
Comment #28.0
dags commentedAdding new information to the issue summary.
Comment #29
dags commentedIn comment #19, webchick degraded the priority from major to normal as it was believed this was a bug in the multistep module. Setting back to major because this has been reproduced in core.
Comment #30
dags commentedI'm also unassigning this from myself in case anyone else wants to jump in.
Comment #31
xjmThanks @dags.
Let's get an automated test for this based on the STR in the summary.
Comment #32
dags commentedFirst draft of a test.
Comment #34
xjmNice work, thanks @dags! That test looks good.
A few suggestions:
Let's add an inline comment above this to make it more scannable, something like "Add a file field to the article content type."
Also, ideally, we should use a test content type rather than article for better decoupling. (See
LocaleContentTestfor an example.) IfFileFieldWidgetTestdoes not currently use a test bundle elsewhere, let's introduce it here first and then file a followup issue to use that test bundle throughout this class (or possibly throughout all classes extendingFileFieldTestBase, depending).In an ideal world, we'd use a test entity instead of node, but that's probably out of scope here. (We wouldn't be able to use
uploadNodeFile(), and the test entity class is in flux with the EntityNG conversion, plus #1822000: Remove Drupal\field_test\Plugin\Entity\Type\TestEntity in favor of EntityTest.)Another inline comment here would be good, like "Create a node with an uploaded file in the field."
I think this should say "and ensure the file is not deleted"?
The
t()can be removed from around the assertion message here. See: http://drupal.org/simpletest-tutorial-drupal7#tComment #35
raycascellaWorking on ticket at Portland2013 sprint. Going to combine patch and test, then reroll after a manual test on my local.
Comment #36
raycascellaLooks like the patch created before may have gone stale. Initial tests show the test passing with or without the update. I'm going to keep looking, though. As I suspect it may have been human error on my part while testing.
Comment #36.0
raycascellaAdding links to related issues
Comment #37
geek-merlin#32: good test @dags!
Nice test, but it looks like this cannot work:
WebTestBase::handleForm (called by ebTestBase::drupalPost / WebTestBase::handleForm
) only can generate a post request to insert values into a already rendered form.
It can NOT do a form alter.
How it CAN work:
* write a tiny helper module that does the form alter
* enable it before your test (not forget to disable it afterwards)
Comment #38
geek-merlin@ RayCascella:
still sprinting?
if yes feel free to reassign you!
if not i just unblock this.
;-)
Comment #39
slashrsm commentedI combined all 3 patches and re-rolled against 8.x.
Will work on other issues based on this patch.
Comment #41
slashrsm commentedAttached patch includes comments from #34 and #37. I also changed
to
I have feeling that we can get array() as an input in here which must processed. Initial patch would ignore this case and display default value instead. I may be wrong, so we probably need to investigate this a bit more.
About bug mentioned in #23... It looks like it also exists in HEAD, which means that was not introduced by this patch. I'll do some more investigation and post another bug if I confirm my assumptions.
Comment #42
slashrsm commentedConfirming default image issue as unrelated bug. Bug report: #2051213: Unable to remove default image from image field/instance.
Comment #42.0
slashrsm commentedFormatting issue summary so it follows the template.
Comment #43
slashrsm commentedIssue summary was updated to reflect latest info.
Comment #44
dags commented@slashrsm: Patch looks good. One minor issue:
Remove this line? I'm not sure if coding standards actually require debug() lines to be removed from tests...
Also, could you post the test separately from the patch? So we can see it fail without the patch and pass with it.
Comment #45
slashrsm commentedI definitely didn't want to leave debug() in there :).
Comment #46
slashrsm commentedAny other comments? Could we RTBC it?
Comment #46.0
slashrsm commentedUpdate summary with latest info.
Comment #47
bmango commentedI manually applied the patch in #45 and it worked well for me. I was having problems saving images with the Multistep module.
Many thanks!
Comment #48
ts145nera commentedHello and thanks,
is correct apply only this?
Comment #50
ts145nera commentedI'm sorry, I've forget to select D7
Comment #51
marthinal commentedWe need to fix this for d8 and then backport to d7.
Comment #52
ts145nera commentedI'm sorry, but I don't work with D8...
I'll try to port this patch in D8 early.
Comment #53
marthinal commentedRerolled. Cannot reproduce manually. Also, this test should fail and works. Anyway, I think we could add this test.
Comment #54
ryan.ryan commentedAssigning for testing
Comment #55
Jalandhar commentedPatch needs reroll
Comment #56
babruix commentedRe-rolled.
Comment #57
babruix commentedComment #59
yesct commentedIssue was assigned in May. Unassigning so it is clear anyone can work on this.
Comment #60
catchComment #64
Oakleeey_97 commentedShot in the dark here..
I've tried applying the patch in the description and it doesn't make a difference at all.
As soon as I press next / previous to go back onto the page I uploaded the file, the file's deleted.
Any help would be massively appreciated.
Comment #65
jonathanshawComment #66
deepakaryan1988Comment #67
deepakaryan1988Tried to reroll this and it was working on my local. Let's hope it would not break in auto testing.
Comment #70
manuel garcia commentedComment #81
quietone commentedThis was a bugsmash target yesterday. Lendude and myself discussed this.
The last report that this problem was occurring and the patch fixed it was in #47, 9 years ago. Then there was a break for 2 years. After that,
in #53 a patch was made to reproduce the problem. That patch passed tests and it was reported that the problem could not be reproduced. The same comment suggest the test could be added. However, if the problem not longer exists, perhaps there is an existing test and this one does not need to be added. Since then there has been no activity.
What remains is to determine if the test is worth adding. I have updated the issue summary.
FWIW, I updated the patch and yes it passes.
Comment #82
quietone commentedAnd no longer a bug report.
Comment #83
pooja saraah commentedFixed failed commands on #81
Attached patch against Drupal 9.5.x
Comment #84
b-prod commented@quietone I don't think this issue is definitively closed, as this bug still appear if you set the access to FALSE on a parent element of the file managed element, but not on the file managed element itself.Actually the point above seems to be caused by late alteration of the form, so this is not related to the current issue.