Problem/Motivation
#59750: Required flag on file forms breaks on validation introduced a change to how the default value is derived.
However this also introduced a bug with simple UploadedFile objects being casted into an array, rather than being wrapped.
https://stackoverflow.com/a/4345609
This breaks existing calls such as:
// Retrieve either the single UploadedFile object or an array of it.
$files = $form_state->getValue('file');
Steps to reproduce
Produce a test which confirms that the value returned by the form state is a valid UploadedFile object.
Proposed resolution
Do a check to see if the return value is not an array and then wrapping accordingly rather than casting.
e.g.
--- return (array) $uploaded_file;
+++ return is_array($uploaded_file) ? $uploaded_file : [$uploaded_file];
Remaining tasks
Provide issue fork/patch.
User interface changes
N/A
API changes
N/A
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #14 | drupal-3352632-11-13.diff | 1018 bytes | mingsong |
| #13 | 3352632-drupal-13.patch | 3.82 KB | mingsong |
| #11 | 3352632-drupal-11.patch | 3.86 KB | mingsong |
| #8 | drupal-3352632-8.patch | 856 bytes | mingsong |
| #4 | 3352632-file-form-state-value-4.diff | 908 bytes | codebymikey |
Issue fork drupal-3352632
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
codebymikey commentedComment #4
codebymikey commentedComment #6
larowlanSeems reasonable, just need to work through the failures
Comment #7
mingsongTest patch #4 by following steps:
1. Login as a user who has permission to access Interface translation import page('/admin/config/regional/translate/import').
2. Upload a translation file (.po) via that form.
3. After submitting that form. An error said
.
Test environment:
Note:
Without having the #4 patch, the translation import is working.
Comment #8
mingsongIf we change line 97 at /core/lib/Drupal/Core/Render/Element/File.php
from
to
All tests on my local are passed.
Here is the new patch.
Comment #9
mingsongComment #10
larowlanthis is an array of arrays, is that correct?
Can we add to the existing test coverage for this case?
See \Drupal\Tests\file\Kernel\ManagedFileTest
Comment #11
mingsongNo worries.
The problem with path #4 is that Symfony\Component\HttpFoundation\File\UploadedFile can not be serialized, according to the error message.
Yes, that is right. A nested array instead of a single array.
Before having the patch #8.
The file element value could be a single array looks like this,
After patching, the file element value will be a nested array.
Sure.
I create a new test /core/tests/Drupal/KernelTests/Core/Element/FileElementTest.php to cover this case.
Here is the new patch with test case.
Comment #12
mingsongComment #13
mingsongThere is a typo in patch #11.
New patch.
Comment #14
mingsongComment #15
codebymikey commentedAppreciate the tests @Mingsong and finding where the proposed patch breaks things during serializations, the issue is that calls like this:
Should ideally still return an array of
\Symfony\Component\HttpFoundation\File\UploadedFileinstances, having it being casted to an array makes it harder to retrieve the original value from the form state.Unless we document that uploaded files should never be read from the
$form_statebut instead directly from the request (as core seems to handle it in most of its code).Or potentially introduce a new serializable class to decorate
\Symfony\Component\HttpFoundation\File\UploadedFileand use that inside the form state (so that it can work in batch contexts).edit: Usage of the current patch can lead to crashing of config entity forms which make use of file uploads when editting them (e.g. embed), since
\Drupal\Core\Entity\EntityForm::copyFormValuesToEntity()will copy theUploadedFileinto the entity without checks.So if the entity form page has a Delete button, then during the form serialization for caching, it might throw a serialization exception due to the uploaded file being attached to the entity object.
Comment #16
mingsongYes, I realized what @Mikey pointed too.
The problem is bigger than I thought. More works need to do.
Comment #17
mingsongThis also affects Drupal 10 too.