diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index c333361d4a37f..6b617825c9190 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * changed guessing of DECIMAL to set the `input` option of `NumberType` to string + 4.2.0 ----- diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 49dfd9bfbce6e..34fb04aed283e 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -75,6 +75,7 @@ public function guessType($class, $property) case 'time_immutable': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TimeType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE); case Type::DECIMAL: + return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', ['input' => 'string'], Guess::MEDIUM_CONFIDENCE); case Type::FLOAT: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::MEDIUM_CONFIDENCE); case Type::INTEGER: diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 0d3d468586f6b..ae21b1de9d590 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -47,6 +47,7 @@ CHANGELOG * dispatch `PostSubmitEvent` on `form.post_submit` * dispatch `PreSetDataEvent` on `form.pre_set_data` * dispatch `PostSetDataEvent` on `form.post_set_data` + * added an `input` option to `NumberType` 4.2.0 ----- diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php new file mode 100644 index 0000000000000..27e60b4306336 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Core\DataTransformer; + +use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; + +class StringToFloatTransformer implements DataTransformerInterface +{ + private $scale; + + public function __construct(int $scale = null) + { + $this->scale = $scale; + } + + /** + * @param mixed $value + * + * @return float|null + */ + public function transform($value) + { + if (null === $value) { + return null; + } + + if (!\is_string($value) || !is_numeric($value)) { + throw new TransformationFailedException('Expected a numeric string.'); + } + + return (float) $value; + } + + /** + * @param mixed $value + * + * @return string|null + */ + public function reverseTransform($value) + { + if (null === $value) { + return null; + } + + if (!\is_int($value) && !\is_float($value)) { + throw new TransformationFailedException('Expected a numeric.'); + } + + if ($this->scale > 0) { + return number_format((float) $value, $this->scale, '.', ''); + } + + return (string) $value; + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php b/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php index a0257f0269628..4c1f1fd71f16b 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php @@ -14,6 +14,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer; +use Symfony\Component\Form\Extension\Core\DataTransformer\StringToFloatTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; @@ -33,6 +34,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) $options['rounding_mode'], $options['html5'] ? 'en' : null )); + + if ('string' === $options['input']) { + $builder->addModelTransformer(new StringToFloatTransformer($options['scale'])); + } } /** @@ -56,6 +61,7 @@ public function configureOptions(OptionsResolver $resolver) 'grouping' => false, 'rounding_mode' => NumberToLocalizedStringTransformer::ROUND_HALF_UP, 'compound' => false, + 'input' => 'number', 'html5' => false, ]); @@ -68,7 +74,7 @@ public function configureOptions(OptionsResolver $resolver) NumberToLocalizedStringTransformer::ROUND_UP, NumberToLocalizedStringTransformer::ROUND_CEILING, ]); - + $resolver->setAllowedValues('input', ['number', 'string']); $resolver->setAllowedTypes('scale', ['null', 'int']); $resolver->setAllowedTypes('html5', 'bool'); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php new file mode 100644 index 0000000000000..5726a217da3d9 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\Extension\Core\DataTransformer\StringToFloatTransformer; + +class StringToFloatTransformerTest extends TestCase +{ + private $transformer; + + protected function setUp() + { + $this->transformer = new StringToFloatTransformer(); + } + + protected function tearDown() + { + $this->transformer = null; + } + + public function provideTransformations(): array + { + return [ + [null, null], + ['1', 1.], + ['1.', 1.], + ['1.0', 1.], + ['1.23', 1.23], + ]; + } + + /** + * @dataProvider provideTransformations + */ + public function testTransform($from, $to): void + { + $transformer = new StringToFloatTransformer(); + + $this->assertSame($to, $transformer->transform($from)); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException + */ + public function testFailIfTransformingANonString(): void + { + $transformer = new StringToFloatTransformer(); + $transformer->transform(1.0); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException + */ + public function testFailIfTransformingANonNumericString(): void + { + $transformer = new StringToFloatTransformer(); + $transformer->transform('foobar'); + } + + public function provideReverseTransformations(): array + { + return [ + [null, null], + [1, '1'], + [1., '1'], + [1.0, '1'], + [1.23, '1.23'], + [1, '1.000', 3], + [1.0, '1.000', 3], + [1.23, '1.230', 3], + [1.2344, '1.234', 3], + [1.2345, '1.235', 3], + ]; + } + + /** + * @dataProvider provideReverseTransformations + */ + public function testReverseTransform($from, $to, int $scale = null): void + { + $transformer = new StringToFloatTransformer($scale); + + $this->assertSame($to, $transformer->reverseTransform($from)); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException + */ + public function testFailIfReverseTransformingANonNumeric(): void + { + $transformer = new StringToFloatTransformer(); + $transformer->reverseTransform('foobar'); + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php index 1ab6c8e9fbc76..91b15ca7609ea 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php @@ -27,7 +27,7 @@ protected function setUp() \Locale::setDefault('de_DE'); } - public function testDefaultFormatting() + public function testDefaultFormatting(): void { $form = $this->factory->create(static::TESTED_TYPE); $form->setData('12345.67890'); @@ -35,7 +35,7 @@ public function testDefaultFormatting() $this->assertSame('12345,679', $form->createView()->vars['value']); } - public function testDefaultFormattingWithGrouping() + public function testDefaultFormattingWithGrouping(): void { $form = $this->factory->create(static::TESTED_TYPE, null, ['grouping' => true]); $form->setData('12345.67890'); @@ -43,7 +43,7 @@ public function testDefaultFormattingWithGrouping() $this->assertSame('12.345,679', $form->createView()->vars['value']); } - public function testDefaultFormattingWithScale() + public function testDefaultFormattingWithScale(): void { $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 2]); $form->setData('12345.67890'); @@ -51,7 +51,23 @@ public function testDefaultFormattingWithScale() $this->assertSame('12345,68', $form->createView()->vars['value']); } - public function testDefaultFormattingWithRounding() + public function testDefaultFormattingWithScaleFloat(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 2]); + $form->setData(12345.67890); + + $this->assertSame('12345,68', $form->createView()->vars['value']); + } + + public function testDefaultFormattingWithScaleAndStringInput(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 2, 'input' => 'string']); + $form->setData('12345.67890'); + + $this->assertSame('12345,68', $form->createView()->vars['value']); + } + + public function testDefaultFormattingWithRounding(): void { $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 0, 'rounding_mode' => \NumberFormatter::ROUND_UP]); $form->setData('12345.54321'); @@ -76,6 +92,46 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = '10', $expectedD $this->assertSame($expectedData, $form->getData()); } + public function testSubmitNumericInput(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'number']); + $form->submit('1,234'); + + $this->assertSame(1.234, $form->getData()); + $this->assertSame(1.234, $form->getNormData()); + $this->assertSame('1,234', $form->getViewData()); + } + + public function testSubmitNumericInputWithScale(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'number', 'scale' => 2]); + $form->submit('1,234'); + + $this->assertSame(1.23, $form->getData()); + $this->assertSame(1.23, $form->getNormData()); + $this->assertSame('1,23', $form->getViewData()); + } + + public function testSubmitStringInput(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'string']); + $form->submit('1,234'); + + $this->assertSame('1.234', $form->getData()); + $this->assertSame(1.234, $form->getNormData()); + $this->assertSame('1,234', $form->getViewData()); + } + + public function testSubmitStringInputWithScale(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'string', 'scale' => 2]); + $form->submit('1,234'); + + $this->assertSame('1.23', $form->getData()); + $this->assertSame(1.23, $form->getNormData()); + $this->assertSame('1,23', $form->getViewData()); + } + public function testIgnoresDefaultLocaleToRenderHtml5NumberWidgets() { $form = $this->factory->create(static::TESTED_TYPE, null, [ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy