Skip to content

[Form][HttpFoundation] Filtering FileBag removes items from CollectionType with FileType #35100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
BoShurik opened this issue Dec 24, 2019 · 5 comments

Comments

@BoShurik
Copy link
Contributor

BoShurik commented Dec 24, 2019

Symfony version(s) affected: all

Description
Similar to #24546

When file is not uploaded I get previously defined one but it's impossible to separate deletion of collection item and not uploading a file

How to reproduce

class IssueType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('files', CollectionType::class, [
                'entry_type' => FileType::class,
                'entry_options' => [
                    'required' => false,
                ],
                'allow_add' => true,
                'allow_delete' => true,
            ])
        ;

        $builder->get('files')->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
            $data = (array)$event->getForm()->getData();
            $exist = [];
            foreach ((array)$event->getData() as $index => $item) {
                // Expect 0 => null for not uploaded file
                if ($item !== null) {
                    $data[$index] = $item; // Replace file
                }

                $exist[$index] = true;
            }

            $keys = array_keys($data);
            foreach ($keys as $key) {
                if (!isset($exist[$key])) {
                    unset($data[$key]); // Remove deleted element
                }
            }

            $event->setData($data);
        });
    }
}
@xabbuh
Copy link
Member

xabbuh commented Dec 24, 2019

I am not sure that I understand what you mean. Can you explain what you expected and what happened instead?

@BoShurik
Copy link
Contributor Author

BoShurik commented Dec 24, 2019

@xabbuh here is the reproducer https://github.com/BoShurik/symfony-file-bag-issue

When you submit form without uploading files, collection with FileTypes resets. I expect to get nulls for not uploaded files.

@xabbuh
Copy link
Member

xabbuh commented Jan 1, 2020

If I understand your concerns correctly, this is just how handling HTML forms work here. If you do not select a file to be uploaded, the client will not send any data for it so it even won't be null on the side where the Form component is doing its job.

So I am going to close here as there is nothing we can change in the component.

If I understood you wrong, please leave a comment with some more explanation and we can consider to reopen.

@xabbuh xabbuh closed this as completed Jan 1, 2020
@BoShurik
Copy link
Contributor Author

BoShurik commented Jan 1, 2020

Problem in HttpFoundation component.

<input type="file" name="single">
<input type="file" name="multiple[]" multiple="multiple">

<input type="file" name="array[0]">
<input type="file" name="array[1]">

<input type="file" name="hash[key0]">
<input type="file" name="hash[key1]">
dump($request->files->get('single')); // null
dump($request->files->get('multiple')); // []
dump($request->files->get('array')); // []
dump($request->files->get('hash')); // { key1 => null, key2 => null }

hash and single receive nulls

The problem is that client do send data: UPLOAD_ERR_NO_FILE - is what I need.

As I can see #24198 was introduced to fix FileType with multiple => true

This causes a problem later when using FileType with multiple option - if no files are sent the form data are [0 => ''] instead of [].

I tried to remove changes made in that PR and all tests in Form component are pass,
FileType with multiple => true is produce correct result ([]) with empty file

dump($request->files->get('single')); // null
dump($request->files->get('multiple')); // [ 0 => null]
dump($request->files->get('array')); // [ 0 => null, 1 => null]
dump($request->files->get('hash')); // { key1 => null, key2 => null }

Does this change considered as a BC break? If so, maybe you know a workaround?
I tried to use string keys for a collection (with DataTransformer) but looks like it is ignored in ResizeFormListener

@BoShurik
Copy link
Contributor Author

BoShurik commented Jan 9, 2020

@xabbuh filtering $request->files can be easily achieved in resulting application, but it's impossible to unfilter it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants