Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 94d9bfb

Browse files
committed
bug #20378 [Form] Fixed show float values as choice value in ChoiceType (yceruto)
This PR was merged into the 2.7 branch. Discussion ---------- [Form] Fixed show float values as choice value in ChoiceType | Q | A | ------------- | --- | Branch? | 2.7 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #13817 | License | MIT | Doc PR | - There is a closed [issue][1] related to this before Symfony 2.7 (when choice value still was the key from the `array`). This issue already happened in 2.7+ but now inside Symfony core. Information ----------- [This method][3] checks whether the given choices can be cast to strings without generating duplicates (3ab8189 in #16705): ```php private function castableToString(array $choices, array &$cache = array()) { foreach ($choices as $choice) { if (is_array($choice)) { if (!$this->castableToString($choice, $cache)) { return false; } continue; } elseif (!is_scalar($choice)) { return false; } elseif (isset($cache[$choice])) { // <---- red breakpoint return false; } $cache[$choice] = true; // <---- red breakpoint } return true; } ``` So it should to keep [scalar values (integer, float, string or boolean)][2] as choice values always (unless have duplicates values). The Problem ----------- But in this situation it doesn't happen: ```php $form = $this->createFormBuilder() ->add('foo', ChoiceType::class, [ 'choices' => [ 'Min' => 0.5, 'Mid' => 1.0, 'Max' => 1.5, ] ]) ->getForm(); ``` **Output:** ```html <select id="form_foo" name="form[foo]"> <option value="0">Min</option> <option value="1">Mid</option> <option value="2">Max</option> </select> ``` [**Why?**][5] If the key of the array is a float number, it's interpreted as integer automatically: ```php // ... $cache[$choice] = true; // when $choice = 0.5: $cache = [0 => true] // when $choice = 1.0: $cache = [0 => true, 1 => true] ``` Then, when `$choice = 1.5` [this sentence][4] `isset($cache[1.5])` returns `true` because really checks `isset($cache[1])` and this key already exists, so `castableToString()` returns `false` (detected as duplicate) and the choices values are generated incrementing integers as values. The PR's Effect ------------- **Before:** ```html <select id="form_foo" name="form[foo]"> <option value="0">Min</option> <option value="1">Mid</option> <option value="2">Max</option> </select> ``` **After:** ```html <select id="form_foo" name="form[foo]"> <option value="0.5">Min</option> <option value="1">Mid</option> <option value="1.5">Max</option> </select> ``` [1]: #13817 [2]: http://php.net/manual/en/function.is-scalar.php [3]: https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php#L228 [4]: https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php#L239 [5]: https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php#L243 Commits ------- 3564228 [Form] Fix show float values as choices values in ChoiceType
2 parents f37ac13 + 3564228 commit 94d9bfb

File tree

2 files changed

+16
-3
lines changed

2 files changed

+16
-3
lines changed

src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,11 @@ private function castableToString(array $choices, array &$cache = array())
236236
continue;
237237
} elseif (!is_scalar($choice)) {
238238
return false;
239-
} elseif (isset($cache[$choice])) {
239+
}
240+
241+
$choice = false === $choice ? '0' : (string) $choice;
242+
243+
if (isset($cache[$choice])) {
240244
return false;
241245
}
242246

src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ protected function createChoiceList()
3434

3535
protected function getChoices()
3636
{
37-
return array(0, 1, '1', 'a', false, true, $this->object, null);
37+
return array(0, 1, 1.5, '1', 'a', false, true, $this->object, null);
3838
}
3939

4040
protected function getValues()
4141
{
42-
return array('0', '1', '2', '3', '4', '5', '6', '7');
42+
return array('0', '1', '2', '3', '4', '5', '6', '7', '8');
4343
}
4444

4545
/**
@@ -162,4 +162,13 @@ public function testGetChoicesForValuesWithContainingEmptyStringAndBooleans()
162162
$this->assertSame(array(0 => true), $choiceList->getChoicesForValues(array('1')));
163163
$this->assertSame(array(0 => false), $choiceList->getChoicesForValues(array('0')));
164164
}
165+
166+
public function testGetChoicesForValuesWithContainingEmptyStringAndFloats()
167+
{
168+
$choiceList = new ArrayChoiceList(array('Empty String' => '', '1/3' => 0.3, '1/2' => 0.5));
169+
170+
$this->assertSame(array(0 => ''), $choiceList->getChoicesForValues(array('')));
171+
$this->assertSame(array(0 => 0.3), $choiceList->getChoicesForValues(array('0.3')));
172+
$this->assertSame(array(0 => 0.5), $choiceList->getChoicesForValues(array('0.5')));
173+
}
165174
}

0 commit comments

Comments
 (0)