bug #25741 [Form] issue-13589: adding custom false-values to BooleanToString transformer (leberknecht)

This PR was squashed before being merged into the 4.1-dev branch (closes #25741).

Discussion
----------

[Form] issue-13589: adding custom false-values to BooleanToString transformer

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #13589
| License       | MIT
| Doc PR        | https://github.com/symfony/symfony-docs/pull/9031

As suggested in #13589 , this PR adds the option to specify custom false-values, so we can use the CheckBoxType to handle strings '1' / '0' and eval them to true / false. While HTTP defines that checkbox types are either submitted=true or not-submitted=false, no matter of what value was submitted, it would be nice to have this option.
Also refs (which read like "the basic idea of the feature was accepted, PR almost done, then something-happend so PR wasnt merged"..?)

https://github.com/symfony/symfony/pull/15054
https://github.com/symfony/symfony/pull/18005

Commits
-------

a3e5ac496f [Form] issue-13589: adding custom false-values to BooleanToString transformer
This commit is contained in:
Fabien Potencier 2018-01-17 21:10:25 +01:00
commit 26e21d1dbb
5 changed files with 70 additions and 4 deletions

View File

@ -19,6 +19,7 @@ CHANGELOG
* removed passing guesser services ids as the fourth argument of `DependencyInjectionExtension::__construct()`
* removed the ability to validate an unsubmitted form.
* removed `ChoiceLoaderInterface` implementation in `TimezoneType`
* added the `false_values` option to the `CheckboxType` which allows to configure custom values which will be treated as `false` during submission
3.4.0
-----

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\Form\Exception\TransformationFailedException;
/**
@ -24,12 +25,19 @@ class BooleanToStringTransformer implements DataTransformerInterface
{
private $trueValue;
private $falseValues;
/**
* @param string $trueValue The value emitted upon transform if the input is true
* @param string $trueValue The value emitted upon transform if the input is true
* @param array $falseValues
*/
public function __construct(string $trueValue)
public function __construct(string $trueValue, array $falseValues = array(null))
{
$this->trueValue = $trueValue;
$this->falseValues = $falseValues;
if (in_array($this->trueValue, $this->falseValues, true)) {
throw new InvalidArgumentException('The specified "true" value is contained in the false-values');
}
}
/**
@ -65,7 +73,7 @@ class BooleanToStringTransformer implements DataTransformerInterface
*/
public function reverseTransform($value)
{
if (null === $value) {
if (in_array($value, $this->falseValues, true)) {
return false;
}

View File

@ -32,7 +32,7 @@ class CheckboxType extends AbstractType
// We cannot solve this case via overriding the "data" option, because
// doing so also calls setDataLocked(true).
$builder->setData(isset($options['data']) ? $options['data'] : false);
$builder->addViewTransformer(new BooleanToStringTransformer($options['value']));
$builder->addViewTransformer(new BooleanToStringTransformer($options['value'], $options['false_values']));
}
/**
@ -59,7 +59,10 @@ class CheckboxType extends AbstractType
'value' => '1',
'empty_data' => $emptyData,
'compound' => false,
'false_values' => array(null),
));
$resolver->setAllowedTypes('false_values', 'array');
}
/**

View File

@ -68,4 +68,26 @@ class BooleanToStringTransformerTest extends TestCase
$this->assertTrue($this->transformer->reverseTransform(''));
$this->assertFalse($this->transformer->reverseTransform(null));
}
public function testCustomFalseValues()
{
$customFalseTransformer = new BooleanToStringTransformer(self::TRUE_VALUE, array('0', 'myFalse', true));
$this->assertFalse($customFalseTransformer->reverseTransform('myFalse'));
$this->assertFalse($customFalseTransformer->reverseTransform('0'));
$this->assertFalse($customFalseTransformer->reverseTransform(true));
}
/**
* @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
*/
public function testTrueValueContainedInFalseValues()
{
new BooleanToStringTransformer('0', array(null, '0'));
}
public function testBeStrictOnTrueInFalseValueCheck()
{
$transformer = new BooleanToStringTransformer('0', array(null, false));
$this->assertInstanceOf(BooleanToStringTransformer::class, $transformer);
}
}

View File

@ -173,6 +173,38 @@ class CheckboxTypeTest extends BaseTypeTest
);
}
/**
* @dataProvider provideCustomFalseValues
*/
public function testCustomFalseValues($falseValue)
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
'false_values' => array($falseValue),
));
$form->submit($falseValue);
$this->assertFalse($form->getData());
}
public function provideCustomFalseValues()
{
return array(
array(''),
array('false'),
array('0'),
);
}
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
*/
public function testDontAllowNonArrayFalseValues()
{
$this->expectExceptionMessageRegExp('/"false_values" with value "invalid" is expected to be of type "array"/');
$this->factory->create(static::TESTED_TYPE, null, array(
'false_values' => 'invalid',
));
}
public function testSubmitNull($expected = null, $norm = null, $view = null)
{
parent::testSubmitNull(false, false, null);