Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit06a1a1b

Browse files
committed
feature#35729 [Form] Correctly round model with PercentType and add a rounding_mode option (VincentLanglet)
This PR was squashed before being merged into the 5.1-dev branch.Discussion----------[Form] Correctly round model with PercentType and add a rounding_mode option| Q | A| ------------- | ---| Branch? | master| Bug fix? | yes| New feature? | yes| Deprecations? | no| Tickets |Fix#35296| License | MIT| Doc PR |symfony/symfony-docs#13138Commits-------d97565d [Form] Correctly round model with PercentType and add a rounding_mode option
2 parentse0bddee +d97565d commit06a1a1b

File tree

4 files changed

+229
-4
lines changed

4 files changed

+229
-4
lines changed

‎src/Symfony/Component/Form/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ CHANGELOG
1414
is deprecated. The method will be added to the interface in 6.0.
1515
* Implementing the`FormConfigBuilderInterface` without implementing the`setIsEmptyCallback()` method
1616
is deprecated. The method will be added to the interface in 6.0.
17+
* Added a`rounding_mode` option for the PercentType and correctly round the value when submitted
1718

1819
5.0.0
1920
-----

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

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,55 @@
2323
*/
2424
class PercentToLocalizedStringTransformerimplements DataTransformerInterface
2525
{
26+
/**
27+
* Rounds a number towards positive infinity.
28+
*
29+
* Rounds 1.4 to 2 and -1.4 to -1.
30+
*/
31+
constROUND_CEILING = \NumberFormatter::ROUND_CEILING;
32+
33+
/**
34+
* Rounds a number towards negative infinity.
35+
*
36+
* Rounds 1.4 to 1 and -1.4 to -2.
37+
*/
38+
constROUND_FLOOR = \NumberFormatter::ROUND_FLOOR;
39+
40+
/**
41+
* Rounds a number away from zero.
42+
*
43+
* Rounds 1.4 to 2 and -1.4 to -2.
44+
*/
45+
constROUND_UP = \NumberFormatter::ROUND_UP;
46+
47+
/**
48+
* Rounds a number towards zero.
49+
*
50+
* Rounds 1.4 to 1 and -1.4 to -1.
51+
*/
52+
constROUND_DOWN = \NumberFormatter::ROUND_DOWN;
53+
54+
/**
55+
* Rounds to the nearest number and halves to the next even number.
56+
*
57+
* Rounds 2.5, 1.6 and 1.5 to 2 and 1.4 to 1.
58+
*/
59+
constROUND_HALF_EVEN = \NumberFormatter::ROUND_HALFEVEN;
60+
61+
/**
62+
* Rounds to the nearest number and halves away from zero.
63+
*
64+
* Rounds 2.5 to 3, 1.6 and 1.5 to 2 and 1.4 to 1.
65+
*/
66+
constROUND_HALF_UP = \NumberFormatter::ROUND_HALFUP;
67+
68+
/**
69+
* Rounds to the nearest number and halves towards zero.
70+
*
71+
* Rounds 2.5 and 1.6 to 2, 1.5 and 1.4 to 1.
72+
*/
73+
constROUND_HALF_DOWN = \NumberFormatter::ROUND_HALFDOWN;
74+
2675
constFRACTIONAL ='fractional';
2776
constINTEGER ='integer';
2877

@@ -31,6 +80,8 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface
3180
self::INTEGER,
3281
];
3382

83+
protected$roundingMode;
84+
3485
private$type;
3586
private$scale;
3687

@@ -42,7 +93,7 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface
4293
*
4394
* @throws UnexpectedTypeException if the given value of type is unknown
4495
*/
45-
publicfunction__construct(int$scale =null,string$type =null)
96+
publicfunction__construct(int$scale =null,string$type =null, ?int$roundingMode =self::ROUND_HALF_UP)
4697
{
4798
if (null ===$scale) {
4899
$scale =0;
@@ -52,12 +103,17 @@ public function __construct(int $scale = null, string $type = null)
52103
$type =self::FRACTIONAL;
53104
}
54105

106+
if (null ===$roundingMode) {
107+
$roundingMode =self::ROUND_HALF_UP;
108+
}
109+
55110
if (!\in_array($type,self::$types,true)) {
56111
thrownewUnexpectedTypeException($type,implode('", "',self::$types));
57112
}
58113

59114
$this->type =$type;
60115
$this->scale =$scale;
116+
$this->roundingMode =$roundingMode;
61117
}
62118

63119
/**
@@ -166,7 +222,7 @@ public function reverseTransform($value)
166222
}
167223
}
168224

169-
return$result;
225+
return$this->round($result);
170226
}
171227

172228
/**
@@ -179,7 +235,58 @@ protected function getNumberFormatter()
179235
$formatter =new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL);
180236

181237
$formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS,$this->scale);
238+
$formatter->setAttribute(\NumberFormatter::ROUNDING_MODE,$this->roundingMode);
182239

183240
return$formatter;
184241
}
242+
243+
/**
244+
* Rounds a number according to the configured scale and rounding mode.
245+
*
246+
* @param int|float $number A number
247+
*
248+
* @return int|float The rounded number
249+
*/
250+
privatefunctionround($number)
251+
{
252+
if (null !==$this->scale &&null !==$this->roundingMode) {
253+
// shift number to maintain the correct scale during rounding
254+
$roundingCoef =pow(10,$this->scale);
255+
256+
if (self::FRACTIONAL ==$this->type) {
257+
$roundingCoef *=100;
258+
}
259+
260+
// string representation to avoid rounding errors, similar to bcmul()
261+
$number = (string) ($number *$roundingCoef);
262+
263+
switch ($this->roundingMode) {
264+
caseself::ROUND_CEILING:
265+
$number =ceil($number);
266+
break;
267+
caseself::ROUND_FLOOR:
268+
$number =floor($number);
269+
break;
270+
caseself::ROUND_UP:
271+
$number =$number >0 ?ceil($number) :floor($number);
272+
break;
273+
caseself::ROUND_DOWN:
274+
$number =$number >0 ?floor($number) :ceil($number);
275+
break;
276+
caseself::ROUND_HALF_EVEN:
277+
$number =round($number,0,PHP_ROUND_HALF_EVEN);
278+
break;
279+
caseself::ROUND_HALF_UP:
280+
$number =round($number,0,PHP_ROUND_HALF_UP);
281+
break;
282+
caseself::ROUND_HALF_DOWN:
283+
$number =round($number,0,PHP_ROUND_HALF_DOWN);
284+
break;
285+
}
286+
287+
$number =1 ===$roundingCoef ? (int)$number :$number /$roundingCoef;
288+
}
289+
290+
return$number;
291+
}
185292
}

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespaceSymfony\Component\Form\Extension\Core\Type;
1313

1414
useSymfony\Component\Form\AbstractType;
15+
useSymfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer;
1516
useSymfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer;
1617
useSymfony\Component\Form\FormBuilderInterface;
1718
useSymfony\Component\Form\FormInterface;
@@ -25,7 +26,11 @@ class PercentType extends AbstractType
2526
*/
2627
publicfunctionbuildForm(FormBuilderInterface$builder,array$options)
2728
{
28-
$builder->addViewTransformer(newPercentToLocalizedStringTransformer($options['scale'],$options['type']));
29+
$builder->addViewTransformer(newPercentToLocalizedStringTransformer(
30+
$options['scale'],
31+
$options['type'],
32+
$options['rounding_mode']
33+
));
2934
}
3035

3136
/**
@@ -43,6 +48,7 @@ public function configureOptions(OptionsResolver $resolver)
4348
{
4449
$resolver->setDefaults([
4550
'scale' =>0,
51+
'rounding_mode' => NumberToLocalizedStringTransformer::ROUND_HALF_UP,
4652
'symbol' =>'%',
4753
'type' =>'fractional',
4854
'compound' =>false,
@@ -52,7 +58,15 @@ public function configureOptions(OptionsResolver $resolver)
5258
'fractional',
5359
'integer',
5460
]);
55-
61+
$resolver->setAllowedValues('rounding_mode', [
62+
NumberToLocalizedStringTransformer::ROUND_FLOOR,
63+
NumberToLocalizedStringTransformer::ROUND_DOWN,
64+
NumberToLocalizedStringTransformer::ROUND_HALF_DOWN,
65+
NumberToLocalizedStringTransformer::ROUND_HALF_EVEN,
66+
NumberToLocalizedStringTransformer::ROUND_HALF_UP,
67+
NumberToLocalizedStringTransformer::ROUND_UP,
68+
NumberToLocalizedStringTransformer::ROUND_CEILING,
69+
]);
5670
$resolver->setAllowedTypes('scale','int');
5771
$resolver->setAllowedTypes('symbol', ['bool','string']);
5872
}

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

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,109 @@ public function testReverseTransform()
7979
$this->assertEquals(2,$transformer->reverseTransform('200'));
8080
}
8181

82+
publicfunctionreverseTransformWithRoundingProvider()
83+
{
84+
return [
85+
// towards positive infinity (1.6 -> 2, -1.6 -> -1)
86+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.5',35, PercentToLocalizedStringTransformer::ROUND_CEILING],
87+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.4',35, PercentToLocalizedStringTransformer::ROUND_CEILING],
88+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.45',3.5, PercentToLocalizedStringTransformer::ROUND_CEILING],
89+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.44',3.5, PercentToLocalizedStringTransformer::ROUND_CEILING],
90+
[null,0,'34.5',0.35, PercentToLocalizedStringTransformer::ROUND_CEILING],
91+
[null,0,'34.4',0.35, PercentToLocalizedStringTransformer::ROUND_CEILING],
92+
[null,1,'3.45',0.035, PercentToLocalizedStringTransformer::ROUND_CEILING],
93+
[null,1,'3.44',0.035, PercentToLocalizedStringTransformer::ROUND_CEILING],
94+
// towards negative infinity (1.6 -> 1, -1.6 -> -2)
95+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.5',34, PercentToLocalizedStringTransformer::ROUND_FLOOR],
96+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.4',34, PercentToLocalizedStringTransformer::ROUND_FLOOR],
97+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.45',3.4, PercentToLocalizedStringTransformer::ROUND_FLOOR],
98+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.44',3.4, PercentToLocalizedStringTransformer::ROUND_FLOOR],
99+
[null,0,'34.5',0.34, PercentToLocalizedStringTransformer::ROUND_FLOOR],
100+
[null,0,'34.4',0.34, PercentToLocalizedStringTransformer::ROUND_FLOOR],
101+
[null,1,'3.45',0.034, PercentToLocalizedStringTransformer::ROUND_FLOOR],
102+
[null,1,'3.44',0.034, PercentToLocalizedStringTransformer::ROUND_FLOOR],
103+
// away from zero (1.6 -> 2, -1.6 -> 2)
104+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.5',35, PercentToLocalizedStringTransformer::ROUND_UP],
105+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.4',35, PercentToLocalizedStringTransformer::ROUND_UP],
106+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.45',3.5, PercentToLocalizedStringTransformer::ROUND_UP],
107+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.44',3.5, PercentToLocalizedStringTransformer::ROUND_UP],
108+
[null,0,'34.5',0.35, PercentToLocalizedStringTransformer::ROUND_UP],
109+
[null,0,'34.4',0.35, PercentToLocalizedStringTransformer::ROUND_UP],
110+
[null,1,'3.45',0.035, PercentToLocalizedStringTransformer::ROUND_UP],
111+
[null,1,'3.44',0.035, PercentToLocalizedStringTransformer::ROUND_UP],
112+
// towards zero (1.6 -> 1, -1.6 -> -1)
113+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.5',34, PercentToLocalizedStringTransformer::ROUND_DOWN],
114+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.4',34, PercentToLocalizedStringTransformer::ROUND_DOWN],
115+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.45',3.4, PercentToLocalizedStringTransformer::ROUND_DOWN],
116+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.44',3.4, PercentToLocalizedStringTransformer::ROUND_DOWN],
117+
[PercentToLocalizedStringTransformer::INTEGER,2,'37.37',37.37, PercentToLocalizedStringTransformer::ROUND_DOWN],
118+
[PercentToLocalizedStringTransformer::INTEGER,2,'2.01',2.01, PercentToLocalizedStringTransformer::ROUND_DOWN],
119+
[null,0,'34.5',0.34, PercentToLocalizedStringTransformer::ROUND_DOWN],
120+
[null,0,'34.4',0.34, PercentToLocalizedStringTransformer::ROUND_DOWN],
121+
[null,1,'3.45',0.034, PercentToLocalizedStringTransformer::ROUND_DOWN],
122+
[null,1,'3.44',0.034, PercentToLocalizedStringTransformer::ROUND_DOWN],
123+
[null,2,'37.37',0.3737, PercentToLocalizedStringTransformer::ROUND_DOWN],
124+
[null,2,'2.01',0.0201, PercentToLocalizedStringTransformer::ROUND_DOWN],
125+
// round halves (.5) to the next even number
126+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.6',35, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
127+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.5',34, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
128+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.4',34, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
129+
[PercentToLocalizedStringTransformer::INTEGER,0,'33.5',34, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
130+
[PercentToLocalizedStringTransformer::INTEGER,0,'32.5',32, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
131+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.46',3.5, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
132+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.45',3.4, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
133+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.44',3.4, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
134+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.35',3.4, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
135+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.25',3.2, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
136+
[null,0,'34.6',0.35, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
137+
[null,0,'34.5',0.34, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
138+
[null,0,'34.4',0.34, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
139+
[null,0,'33.5',0.34, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
140+
[null,0,'32.5',0.32, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
141+
[null,1,'3.46',0.035, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
142+
[null,1,'3.45',0.034, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
143+
[null,1,'3.44',0.034, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
144+
[null,1,'3.35',0.034, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
145+
[null,1,'3.25',0.032, PercentToLocalizedStringTransformer::ROUND_HALF_EVEN],
146+
// round halves (.5) away from zero
147+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.6',35, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
148+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.5',35, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
149+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.4',34, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
150+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.46',3.5, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
151+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.45',3.5, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
152+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.44',3.4, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
153+
[null,0,'34.6',0.35, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
154+
[null,0,'34.5',0.35, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
155+
[null,0,'34.4',0.34, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
156+
[null,1,'3.46',0.035, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
157+
[null,1,'3.45',0.035, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
158+
[null,1,'3.44',0.034, PercentToLocalizedStringTransformer::ROUND_HALF_UP],
159+
// round halves (.5) towards zero
160+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.6',35, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
161+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.5',34, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
162+
[PercentToLocalizedStringTransformer::INTEGER,0,'34.4',34, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
163+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.46',3.5, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
164+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.45',3.4, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
165+
[PercentToLocalizedStringTransformer::INTEGER,1,'3.44',3.4, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
166+
[null,0,'34.6',0.35, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
167+
[null,0,'34.5',0.34, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
168+
[null,0,'34.4',0.34, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
169+
[null,1,'3.46',0.035, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
170+
[null,1,'3.45',0.034, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
171+
[null,1,'3.44',0.034, PercentToLocalizedStringTransformer::ROUND_HALF_DOWN],
172+
];
173+
}
174+
175+
/**
176+
* @dataProvider reverseTransformWithRoundingProvider
177+
*/
178+
publicfunctiontestReverseTransformWithRounding($type,$scale,$input,$output,$roundingMode)
179+
{
180+
$transformer =newPercentToLocalizedStringTransformer($scale,$type,$roundingMode);
181+
182+
$this->assertSame($output,$transformer->reverseTransform($input));
183+
}
184+
82185
publicfunctiontestReverseTransformEmpty()
83186
{
84187
$transformer =newPercentToLocalizedStringTransformer();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp