Skip to content

Commit

Permalink
[Form] Handle false as empty value on expanded choices
Browse files Browse the repository at this point in the history
  • Loading branch information
fancyweb committed Mar 6, 2020
1 parent bd0bf52 commit 1a366bc
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 1 deletion.
Expand Up @@ -33,6 +33,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
// doing so also calls setDataLocked(true).
$builder->setData(isset($options['data']) ? $options['data'] : false);
$builder->addViewTransformer(new BooleanToStringTransformer($options['value']));
$builder->setAttribute('_false_is_empty', true); // @internal - A boolean flag to treat false as empty, see Form::isEmpty() - Do not rely on it, it will be removed in Symfony 5.1.
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/Symfony/Component/Form/Form.php
Expand Up @@ -725,7 +725,9 @@ public function isEmpty()
// arrays, countables
((\is_array($this->modelData) || $this->modelData instanceof \Countable) && 0 === \count($this->modelData)) ||
// traversables that are not countable
($this->modelData instanceof \Traversable && 0 === iterator_count($this->modelData));
($this->modelData instanceof \Traversable && 0 === iterator_count($this->modelData)) ||
// @internal - Do not rely on it, it will be removed in Symfony 5.1.
(false === $this->modelData && $this->config->getAttribute('_false_is_empty'));
}

/**
Expand Down
Expand Up @@ -190,4 +190,13 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = 'empty', $expect
$this->assertSame($expectedData, $form->getNormData());
$this->assertSame($expectedData, $form->getData());
}

public function testSubmitNullIsEmpty()
{
$form = $this->factory->create(static::TESTED_TYPE);

$form->submit(null);

$this->assertTrue($form->isEmpty());
}
}
Expand Up @@ -2046,4 +2046,45 @@ public function provideTrimCases()
'Multiple expanded' => [true, true],
];
}

/**
* @dataProvider expandedIsEmptyWhenNoRealChoiceIsSelectedProvider
*/
public function testExpandedIsEmptyWhenNoRealChoiceIsSelected($expected, $submittedData, $multiple, $required, $placeholder)
{
$options = [
'expanded' => true,
'choices' => [
'foo' => 'bar',
],
'multiple' => $multiple,
'required' => $required,
];

if (!$multiple) {
$options['placeholder'] = $placeholder;
}

$form = $this->factory->create(static::TESTED_TYPE, null, $options);

$form->submit($submittedData);

$this->assertSame($expected, $form->isEmpty());
}

public function expandedIsEmptyWhenNoRealChoiceIsSelectedProvider()
{
// Some invalid cases are voluntarily not tested:
// - multiple with placeholder
// - required with placeholder
return [
'Nothing submitted / single / not required / without a placeholder -> should be empty' => [true, null, false, false, null],
'Nothing submitted / single / not required / with a placeholder -> should not be empty' => [false, null, false, false, 'ccc'], // It falls back on the placeholder
'Nothing submitted / single / required / without a placeholder -> should be empty' => [true, null, false, true, null],
'Nothing submitted / single / required / with a placeholder -> should be empty' => [true, null, false, true, 'ccc'],
'Nothing submitted / multiple / not required / without a placeholder -> should be empty' => [true, null, true, false, null],
'Nothing submitted / multiple / required / without a placeholder -> should be empty' => [true, null, true, true, null],
'Placeholder submitted / single / not required / with a placeholder -> should not be empty' => [false, '', false, false, 'ccc'], // The placeholder is a selected value
];
}
}

0 comments on commit 1a366bc

Please sign in to comment.