Skip to content

Commit e337ce9

Browse files
author
Romaric Drigon
committed
Added a "html5" option to PercentType, to render an input[type="number"]. Added tests over PercentType.
1 parent 8535579 commit e337ce9

File tree

4 files changed

+164
-3
lines changed

4 files changed

+164
-3
lines changed

src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,18 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface
3333

3434
private $type;
3535
private $scale;
36+
private $html5Format;
3637

3738
/**
3839
* @see self::$types for a list of supported types
3940
*
4041
* @param int $scale The scale
4142
* @param string $type One of the supported types
43+
* @param bool $html5Format Use a HTML5 specific format, as per https://www.w3.org/TR/html51/sec-forms.html#date-time-and-number-formats
4244
*
4345
* @throws UnexpectedTypeException if the given value of type is unknown
4446
*/
45-
public function __construct(int $scale = null, string $type = null)
47+
public function __construct(int $scale = null, string $type = null, bool $html5Format = false)
4648
{
4749
if (null === $scale) {
4850
$scale = 0;
@@ -58,6 +60,7 @@ public function __construct(int $scale = null, string $type = null)
5860

5961
$this->type = $type;
6062
$this->scale = $scale;
63+
$this->html5Format = $html5Format;
6164
}
6265

6366
/**
@@ -176,7 +179,13 @@ public function reverseTransform($value)
176179
*/
177180
protected function getNumberFormatter()
178181
{
179-
$formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL);
182+
// Values used in HTML5 number inputs should be formatted as in "1234.5", ie. 'en' format without grouping,
183+
// according to https://www.w3.org/TR/html51/sec-forms.html#date-time-and-number-formats
184+
$formatter = new \NumberFormatter($this->html5Format ? 'en' : \Locale::getDefault(), \NumberFormatter::DECIMAL);
185+
186+
if ($this->html5Format) {
187+
$formatter->setAttribute(\NumberFormatter::GROUPING_USED, 0);
188+
}
180189

181190
$formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->scale);
182191

src/Symfony/Component/Form/Extension/Core/Type/PercentType.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class PercentType extends AbstractType
2525
*/
2626
public function buildForm(FormBuilderInterface $builder, array $options)
2727
{
28-
$builder->addViewTransformer(new PercentToLocalizedStringTransformer($options['scale'], $options['type']));
28+
$builder->addViewTransformer(new PercentToLocalizedStringTransformer($options['scale'], $options['type'], $options['html5']));
2929
}
3030

3131
/**
@@ -34,6 +34,10 @@ public function buildForm(FormBuilderInterface $builder, array $options)
3434
public function buildView(FormView $view, FormInterface $form, array $options)
3535
{
3636
$view->vars['symbol'] = $options['symbol'];
37+
38+
if ($options['html5']) {
39+
$view->vars['type'] = 'number';
40+
}
3741
}
3842

3943
/**
@@ -46,6 +50,7 @@ public function configureOptions(OptionsResolver $resolver)
4650
'symbol' => '%',
4751
'type' => 'fractional',
4852
'compound' => false,
53+
'html5' => false,
4954
]);
5055

5156
$resolver->setAllowedValues('type', [
@@ -55,6 +60,7 @@ public function configureOptions(OptionsResolver $resolver)
5560

5661
$resolver->setAllowedTypes('scale', 'int');
5762
$resolver->setAllowedTypes('symbol', ['bool', 'string']);
63+
$resolver->setAllowedTypes('html5', 'bool');
5864
}
5965

6066
/**

src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,83 @@ public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte()
294294

295295
$transformer->reverseTransform("12\xc2\xa0345,678foo");
296296
}
297+
298+
public function testTransformForHtml5Format()
299+
{
300+
$transformer = new PercentToLocalizedStringTransformer(null, null, true);
301+
302+
// Since we test against "de_CH", we need the full implementation
303+
IntlTestHelper::requireFullIntl($this, false);
304+
305+
\Locale::setDefault('de_CH');
306+
307+
$this->assertEquals('10', $transformer->transform(0.105));
308+
$this->assertEquals('200000', $transformer->transform(2000));
309+
}
310+
311+
public function testTransformForHtml5FormatWithInteger()
312+
{
313+
$transformer = new PercentToLocalizedStringTransformer(null, 'integer', true);
314+
315+
// Since we test against "de_CH", we need the full implementation
316+
IntlTestHelper::requireFullIntl($this, false);
317+
318+
\Locale::setDefault('de_CH');
319+
320+
$this->assertEquals('0', $transformer->transform(0.1));
321+
$this->assertEquals('1234', $transformer->transform(1234));
322+
}
323+
324+
public function testTransformForHtml5FormatWithScale()
325+
{
326+
// Since we test against "de_CH", we need the full implementation
327+
IntlTestHelper::requireFullIntl($this, false);
328+
329+
\Locale::setDefault('de_CH');
330+
331+
$transformer = new PercentToLocalizedStringTransformer(2, null, true);
332+
333+
$this->assertEquals('12.34', $transformer->transform(0.1234));
334+
}
335+
336+
public function testReverseTransformForHtml5Format()
337+
{
338+
// Since we test against "de_CH", we need the full implementation
339+
IntlTestHelper::requireFullIntl($this, false);
340+
341+
\Locale::setDefault('de_CH');
342+
343+
$transformer = new PercentToLocalizedStringTransformer(null, null, true);
344+
345+
$this->assertEquals(0.015, $transformer->reverseTransform('1.5'));
346+
$this->assertEquals(0.15, $transformer->reverseTransform('15'));
347+
$this->assertEquals(2000, $transformer->reverseTransform('200000'));
348+
}
349+
350+
public function testReverseTransformForHtml5FormatWithInteger()
351+
{
352+
// Since we test against "de_CH", we need the full implementation
353+
IntlTestHelper::requireFullIntl($this, false);
354+
355+
\Locale::setDefault('de_CH');
356+
357+
$transformer = new PercentToLocalizedStringTransformer(null, 'integer', true);
358+
359+
$this->assertEquals(10, $transformer->reverseTransform('10'));
360+
$this->assertEquals(15, $transformer->reverseTransform('15'));
361+
$this->assertEquals(12, $transformer->reverseTransform('12'));
362+
$this->assertEquals(200, $transformer->reverseTransform('200'));
363+
}
364+
365+
public function testReverseTransformForHtml5FormatWithScale()
366+
{
367+
// Since we test against "de_CH", we need the full implementation
368+
IntlTestHelper::requireFullIntl($this, false);
369+
370+
\Locale::setDefault('de_CH');
371+
372+
$transformer = new PercentToLocalizedStringTransformer(2, null, true);
373+
374+
$this->assertEquals(0.1234, $transformer->reverseTransform('12.34'));
375+
}
297376
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
13+
14+
use Symfony\Component\Intl\Util\IntlTestHelper;
15+
16+
class PercentTypeTest extends BaseTypeTest
17+
{
18+
const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\PercentType';
19+
20+
private $defaultLocale;
21+
22+
protected function setUp(): void
23+
{
24+
// we test against different locales, so we need the full
25+
// implementation
26+
IntlTestHelper::requireFullIntl($this, false);
27+
28+
parent::setUp();
29+
30+
$this->defaultLocale = \Locale::getDefault();
31+
}
32+
33+
protected function tearDown(): void
34+
{
35+
parent::tearDown();
36+
37+
\Locale::setDefault($this->defaultLocale);
38+
}
39+
40+
public function testSubmitNull($expected = null, $norm = null, $view = null)
41+
{
42+
parent::testSubmitNull($expected, $norm, '');
43+
}
44+
45+
public function testSubmitNullUsesDefaultEmptyData($emptyData = '10', $expectedData = 0.1)
46+
{
47+
$form = $this->factory->create(static::TESTED_TYPE, null, [
48+
'empty_data' => $emptyData,
49+
]);
50+
$form->submit(null);
51+
52+
$this->assertSame($emptyData, $form->getViewData());
53+
$this->assertSame($expectedData, $form->getNormData());
54+
$this->assertSame($expectedData, $form->getData());
55+
}
56+
57+
public function testHtml5EnablesSpecificFormatting()
58+
{
59+
\Locale::setDefault('de_CH');
60+
61+
$form = $this->factory->create(static::TESTED_TYPE, null, ['html5' => true, 'scale' => 2, 'type' => 'integer']);
62+
$form->setData('1234.56');
63+
64+
$this->assertSame('1234.56', $form->createView()->vars['value']);
65+
$this->assertSame('number', $form->createView()->vars['type']);
66+
}
67+
}

0 commit comments

Comments
 (0)