-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
[Form][DX] FileType "multiple" fixes #20418
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,12 +12,37 @@ | |
namespace Symfony\Component\Form\Extension\Core\Type; | ||
|
||
use Symfony\Component\Form\AbstractType; | ||
use Symfony\Component\Form\FormBuilderInterface; | ||
use Symfony\Component\Form\FormEvent; | ||
use Symfony\Component\Form\FormEvents; | ||
use Symfony\Component\Form\FormInterface; | ||
use Symfony\Component\Form\FormView; | ||
use Symfony\Component\OptionsResolver\Options; | ||
use Symfony\Component\OptionsResolver\OptionsResolver; | ||
|
||
class FileType extends AbstractType | ||
{ | ||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function buildForm(FormBuilderInterface $builder, array $options) | ||
{ | ||
if ($options['multiple']) { | ||
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { | ||
$form = $event->getForm(); | ||
$data = $event->getData(); | ||
|
||
// submitted data for an input file (not required) without choosing any file | ||
if (array(null) === $data) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still not sure about this, by default only 1 So if many inputs are submitted, and only few files are uploaded, we get There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What you describe here looks more like a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But it shouldn't. No matter how IMHO. 😅 If you want multiple inputs, you'll use a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, but that makes the What's the point in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure it needs a data transformer, as this is only about filtering out null values. Again; to enforce the This does not apply in any way to other types. Doing weird things with textypes, ie. changing
or without validators;
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Imho it's already cover, we can avoid that with * @Assert\All({
* @Assert\File(mimeTypes = {"application/pdf", "application/x-pdf"})
* })
*/
private $brochures; Also by manipulating the DOM or doing a raw request we can guarantee a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we're letting the user deal with it then. Just saying, not everybody probably expects this behavior (leaving a hole in your architecture). But we'er good then. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Exactly, the form type only should cover the normal expected behavior.
AFAIK this hole is responsibility of constraints/validators. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Imo. it should define consistent behavior :)
Just saying we could avoid the whole thing by filtering out nulls out-of-the-box, having consistent behavior :) But im fine with keeping it in user-land as well. The point is clear, thanks for letting me clarify! if everbody's in favor with this approach, im as well 👍 |
||
$emptyData = $form->getConfig()->getEmptyData(); | ||
|
||
$data = is_callable($emptyData) ? call_user_func($emptyData, $form, $data) : $emptyData; | ||
$event->setData($data); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
|
@@ -39,20 +64,26 @@ public function buildView(FormView $view, FormInterface $form, array $options) | |
*/ | ||
public function finishView(FormView $view, FormInterface $form, array $options) | ||
{ | ||
$view | ||
->vars['multipart'] = true | ||
; | ||
$view->vars['multipart'] = true; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function configureOptions(OptionsResolver $resolver) | ||
{ | ||
$dataClass = function (Options $options) { | ||
return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File'; | ||
}; | ||
|
||
$emptyData = function (Options $options) { | ||
return $options['multiple'] ? array() : null; | ||
}; | ||
|
||
$resolver->setDefaults(array( | ||
'compound' => false, | ||
'data_class' => 'Symfony\Component\HttpFoundation\File\File', | ||
'empty_data' => null, | ||
'data_class' => $dataClass, | ||
'empty_data' => $emptyData, | ||
'multiple' => false, | ||
)); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,33 @@ public function testSubmitEmpty() | |
$this->assertNull($form->getData()); | ||
} | ||
|
||
public function testSubmitEmptyMultiple() | ||
{ | ||
$form = $this->factory->createBuilder('file', null, array( | ||
'multiple' => true, | ||
))->getForm(); | ||
|
||
// submitted data when an input file is uploaded without choosing any file | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does it deserve a test case without default required? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is often the case, for example, when editing a form requesting to change the related image optionally. |
||
$form->submit(array(null)); | ||
|
||
$this->assertSame(array(), $form->getData()); | ||
} | ||
|
||
public function testSetDataMultiple() | ||
{ | ||
$form = $this->factory->createBuilder('file', null, array( | ||
'multiple' => true, | ||
))->getForm(); | ||
|
||
$data = array( | ||
$this->createUploadedFileMock('abcdef', 'first.jpg', true), | ||
$this->createUploadedFileMock('zyxwvu', 'second.jpg', true), | ||
); | ||
|
||
$form->setData($data); | ||
$this->assertSame($data, $form->getData()); | ||
} | ||
|
||
public function testSubmitMultiple() | ||
{ | ||
$form = $this->factory->createBuilder('file', null, array( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we expect multiple nulls here?
array(null, null, ...)
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope!
array(null)
mean no file uploaded, otherwise we expect array ofUploadedFile
instances.