10000 [Form] ObjectChoiceList now compares choices by their value, if a val… · symfony/symfony@ce0efb1 · GitHub
[go: up one dir, main page]

Skip to content

Commit ce0efb1

Browse files
committed
[Form] ObjectChoiceList now compares choices by their value, if a value path is given
1 parent 3cd1c9c commit ce0efb1

File tree

4 files changed

+191
-2
lines changed

4 files changed

+191
-2
lines changed

src/Symfony/Component/Form/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ CHANGELOG
1111
* [BC BREAK] added two optional parameters to FormInterface::getErrors() and
1212
changed the method to return a Symfony\Component\Form\FormErrorIterator
1313
instance instead of an array
14+
* ObjectChoiceList now compares choices by their value, if a value path is
15+
given
1416

1517
2.4.0
1618
-----

src/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ class ChoiceList implements ChoiceListInterface
4141
*
4242
* @var array
4343
*/
44-
private $choices = array();
44+
protected $choices = array();
4545

4646
/**
4747
* The choice values with the indices of the matching choices as keys.
4848
*
4949
* @var array
5050
*/
51-
private $values = array();
51+
protected $values = array();
5252

5353
/**
5454
* The preferred view objects as hierarchy containing also the choice groups

src/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,80 @@ protected function initialize($choices, array $labels, array $preferredChoices)
148148
parent::initialize($choices, $labels, $preferredChoices);
149149
}
150150

151+
/**
152+
* {@inheritdoc}
153+
*/
154+
public function getValuesForChoices(array $choices)
155+
{
156+
if (!$this->valuePath) {
157+
return parent::getValuesForChoices($choices);
158+
}
159+
160+
// Use the value path to compare the choices
161+
$choices = $this->fixChoices($choices);
162+
$values = array();
163+
164+
foreach ($choices as $i => $givenChoice) {
165+
// Ignore non-readable choices
166+
if (!is_object($givenChoice) && !is_array($givenChoice)) {
167+
continue;
168+
}
169+
170+
$givenValue = (string) $this->propertyAccessor->getValue($givenChoice, $this->valuePath);
171+
172+
foreach ($this->values as $value) {
173+
if ($value === $givenValue) {
174+
$values[$i] = $value;
175+
unset($choices[$i]);
176+
177+
if (0 === count($choices)) {
178+
break 2;
179+
}
180+
}
181+
}
182+
}
183+
184+
return $values;
185+
}
186+
187+
/**
188+
* {@inheritdoc}
189+
*
190+
* @deprecated Deprecated since version 2.4, to be removed in 3.0.
191+
*/
192+
public function getIndicesForChoices(array $choices)
193+
{
194+
if (!$this->valuePath) {
195+
return parent::getIndicesForChoices($choices);
196+
}
197+
198+
// Use the value path to compare the choices
199+
$choices = $this->fixChoices($choices);
200+
$indices = array();
201+
202+
foreach ($choices as $i => $givenChoice) {
203+
// Ignore non-readable choices
204+
if (!is_object($givenChoice) && !is_array($givenChoice)) {
205+
continue;
206+
}
207+
208+
$givenValue = (string) $this->propertyAccessor->getValue($givenChoice, $this->valuePath);
209+
210+
foreach ($this->values as $j => $value) {
211+
if ($value === $givenValue) {
212+
$indices[$i] = $j;
213+
unset($choices[$i]);
214+
215+
if (0 === count($choices)) {
216+
break 2;
217+
}
218+
}
219+
}
220+
}
221+
222+
return $indices;
223+
}
224+
151225
/**
152226
* Creates a new unique value for this choice.
153227
*

src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,119 @@ public function testInitArrayThrowsExceptionIfToStringNotFound()
185185
);
186186
}
187187

188+
public function testGetIndicesForChoicesWithValuePath()
189+
{
190+
$this->list = new ObjectChoiceList(
191+
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
192+
'name',
193+
array(),
194+
null,
195+
'name'
196+
);
197+
198+
// Compare by value, not by identity
199+
$choices = array(clone $this->obj1, clone $this->obj2);
200+
$this->assertSame(array($this->index1, $this->index2), $this->list->getIndicesForChoices($choices));
201+
}
202+
203+
public function testGetIndicesForChoicesWithValuePathPreservesKeys()
204+
{
205+
$this->list = new ObjectChoiceList(
206+
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
207+
'name',
208+
array(),
209+
null,
210+
'name'
211+
);
212+
213+
$choices = array(5 => clone $this->obj1, 8 => clone $this->obj2);
214+
$this->assertSame(array(5 => $this->index1, 8 => $this->index2), $this->list->getIndicesForChoices($choices));
215+
}
216+
217+
public function testGetIndicesForChoicesWithValuePathPreservesOrder()
218+
{
219+
$this->list = new ObjectChoiceList(
220+
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
221+
'name',
222+
array(),
223+
null,
224+
'name'
225+
);
226+
227+
$choices = array(clone $this->obj2, clone $this->obj1);
228+
$this->assertSame(array($this->index2, $this->index1), $this->list->getIndicesForChoices($choices));
229+
}
230+
231+
public function testGetIndicesForChoicesWithValuePathIgnoresNonExistingChoices()
232+
{
233+
$this->list = new ObjectChoiceList(
234+
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
235+
'name',
236+
array(),
237+
null,
238+
'name'
239+
);
240+
241+
$choices = array(clone $this->obj1, clone $this->obj2, 'foobar');
242+
$this->assertSame(array($this->index1, $this->index2), $this->list->getIndicesForChoices($choices));
243+
}
244+
245+
public function testGetValuesForChoicesWithValuePath()
246+
{
247+
$this->list = new ObjectChoiceList(
248+
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
249+
'name',
250+
array(),
251+
null,
252+
'name'
253+
);
254+
255+
$choices = array(clone $this->obj1, clone $this->obj2);
256+
$this->assertSame(array('A', 'B'), $this->list->getValuesForChoices($choices));
257+
}
258+
259+
public function testGetValuesForChoicesWithValuePathPreservesKeys()
260+
{
261+
$this->list = new ObjectChoiceList(
262+
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
263+
'name',
264+
array(),
265+
null,
266+
'name'
267+
);
268+
269+
$choices = array(5 => clone $this->obj1, 8 => clone $this->obj2);
270+
$this->assertSame(array(5 => 'A', 8 => 'B'), $this->list->getValuesForChoices($choices));
271+
}
272+
273+
public function testGetValuesForChoicesWithValuePathPreservesOrder()
274+
{
275+
$this->list = new ObjectChoiceList(
276+
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
277+
'name',
278+
array(),
279+
null,
280+
'name'
281+
);
282+
283+
$choices = array(clone $this->obj2, clone $this->obj1);
284+
$this->assertSame(array('B', 'A'), $this->list->getValuesForChoices($choices));
285+
}
286+
287+
public function testGetValuesForChoicesWithValuePathIgnoresNonExistingChoices()
288+
{
289+
$this->list = new ObjectChoiceList(
290+
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
291+
'name',
292+
array(),
293+
null,
294+
'name'
295+
);
296+
297+
$choices = array(clone $this->obj1, clone $this->obj2, 'foobar');
298+
$this->assertSame(array('A', 'B'), $this->list->getValuesForChoices($choices));
299+
}
300+
188301
/**
189302
* @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
190303
*/

0 commit comments

Comments
 (0)
0