feature #10572 [Form] ObjectChoiceList now compares choices by their value, if a value path is given (webmozart)
This PR was merged into the 2.5-dev branch.
Discussion
----------
[Form] ObjectChoiceList now compares choices by their value, if a value path is given
| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #8825
| License | MIT
| Doc PR | -
Commits
-------
ce0efb1
[Form] ObjectChoiceList now compares choices by their value, if a value path is given
This commit is contained in:
commit
2ab27aba8b
@ -12,6 +12,8 @@ CHANGELOG
|
||||
changed the method to return a Symfony\Component\Form\FormErrorIterator
|
||||
instance instead of an array
|
||||
* errors mapped to unsubmitted forms are discarded now
|
||||
* ObjectChoiceList now compares choices by their value, if a value path is
|
||||
given
|
||||
|
||||
2.4.0
|
||||
-----
|
||||
|
@ -41,14 +41,14 @@ class ChoiceList implements ChoiceListInterface
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $choices = array();
|
||||
protected $choices = array();
|
||||
|
||||
/**
|
||||
* The choice values with the indices of the matching choices as keys.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $values = array();
|
||||
protected $values = array();
|
||||
|
||||
/**
|
||||
* The preferred view objects as hierarchy containing also the choice groups
|
||||
|
@ -148,6 +148,80 @@ class ObjectChoiceList extends ChoiceList
|
||||
parent::initialize($choices, $labels, $preferredChoices);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValuesForChoices(array $choices)
|
||||
{
|
||||
if (!$this->valuePath) {
|
||||
return parent::getValuesForChoices($choices);
|
||||
}
|
||||
|
||||
// Use the value path to compare the choices
|
||||
$choices = $this->fixChoices($choices);
|
||||
$values = array();
|
||||
|
||||
foreach ($choices as $i => $givenChoice) {
|
||||
// Ignore non-readable choices
|
||||
if (!is_object($givenChoice) && !is_array($givenChoice)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$givenValue = (string) $this->propertyAccessor->getValue($givenChoice, $this->valuePath);
|
||||
|
||||
foreach ($this->values as $value) {
|
||||
if ($value === $givenValue) {
|
||||
$values[$i] = $value;
|
||||
unset($choices[$i]);
|
||||
|
||||
if (0 === count($choices)) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @deprecated Deprecated since version 2.4, to be removed in 3.0.
|
||||
*/
|
||||
public function getIndicesForChoices(array $choices)
|
||||
{
|
||||
if (!$this->valuePath) {
|
||||
return parent::getIndicesForChoices($choices);
|
||||
}
|
||||
|
||||
// Use the value path to compare the choices
|
||||
$choices = $this->fixChoices($choices);
|
||||
$indices = array();
|
||||
|
||||
foreach ($choices as $i => $givenChoice) {
|
||||
// Ignore non-readable choices
|
||||
if (!is_object($givenChoice) && !is_array($givenChoice)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$givenValue = (string) $this->propertyAccessor->getValue($givenChoice, $this->valuePath);
|
||||
|
||||
foreach ($this->values as $j => $value) {
|
||||
if ($value === $givenValue) {
|
||||
$indices[$i] = $j;
|
||||
unset($choices[$i]);
|
||||
|
||||
if (0 === count($choices)) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new unique value for this choice.
|
||||
*
|
||||
|
@ -185,6 +185,119 @@ class ObjectChoiceListTest extends AbstractChoiceListTest
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetIndicesForChoicesWithValuePath()
|
||||
{
|
||||
$this->list = new ObjectChoiceList(
|
||||
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
|
||||
'name',
|
||||
array(),
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
|
||||
// Compare by value, not by identity
|
||||
$choices = array(clone $this->obj1, clone $this->obj2);
|
||||
$this->assertSame(array($this->index1, $this->index2), $this->list->getIndicesForChoices($choices));
|
||||
}
|
||||
|
||||
public function testGetIndicesForChoicesWithValuePathPreservesKeys()
|
||||
{
|
||||
$this->list = new ObjectChoiceList(
|
||||
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
|
||||
'name',
|
||||
array(),
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
|
||||
$choices = array(5 => clone $this->obj1, 8 => clone $this->obj2);
|
||||
$this->assertSame(array(5 => $this->index1, 8 => $this->index2), $this->list->getIndicesForChoices($choices));
|
||||
}
|
||||
|
||||
public function testGetIndicesForChoicesWithValuePathPreservesOrder()
|
||||
{
|
||||
$this->list = new ObjectChoiceList(
|
||||
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
|
||||
'name',
|
||||
array(),
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
|
||||
$choices = array(clone $this->obj2, clone $this->obj1);
|
||||
$this->assertSame(array($this->index2, $this->index1), $this->list->getIndicesForChoices($choices));
|
||||
}
|
||||
|
||||
public function testGetIndicesForChoicesWithValuePathIgnoresNonExistingChoices()
|
||||
{
|
||||
$this->list = new ObjectChoiceList(
|
||||
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
|
||||
'name',
|
||||
array(),
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
|
||||
$choices = array(clone $this->obj1, clone $this->obj2, 'foobar');
|
||||
$this->assertSame(array($this->index1, $this->index2), $this->list->getIndicesForChoices($choices));
|
||||
}
|
||||
|
||||
public function testGetValuesForChoicesWithValuePath()
|
||||
{
|
||||
$this->list = new ObjectChoiceList(
|
||||
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
|
||||
'name',
|
||||
array(),
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
|
||||
$choices = array(clone $this->obj1, clone $this->obj2);
|
||||
$this->assertSame(array('A', 'B'), $this->list->getValuesForChoices($choices));
|
||||
}
|
||||
|
||||
public function testGetValuesForChoicesWithValuePathPreservesKeys()
|
||||
{
|
||||
$this->list = new ObjectChoiceList(
|
||||
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
|
||||
'name',
|
||||
array(),
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
|
||||
$choices = array(5 => clone $this->obj1, 8 => clone $this->obj2);
|
||||
$this->assertSame(array(5 => 'A', 8 => 'B'), $this->list->getValuesForChoices($choices));
|
||||
}
|
||||
|
||||
public function testGetValuesForChoicesWithValuePathPreservesOrder()
|
||||
{
|
||||
$this->list = new ObjectChoiceList(
|
||||
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
|
||||
'name',
|
||||
array(),
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
|
||||
$choices = array(clone $this->obj2, clone $this->obj1);
|
||||
$this->assertSame(array('B', 'A'), $this->list->getValuesForChoices($choices));
|
||||
}
|
||||
|
||||
public function testGetValuesForChoicesWithValuePathIgnoresNonExistingChoices()
|
||||
{
|
||||
$this->list = new ObjectChoiceList(
|
||||
array($this->obj1, $this->obj2, $this->obj3, $this->obj4),
|
||||
'name',
|
||||
array(),
|
||||
null,
|
||||
'name'
|
||||
);
|
||||
|
||||
$choices = array(clone $this->obj1, clone $this->obj2, 'foobar');
|
||||
$this->assertSame(array('A', 'B'), $this->list->getValuesForChoices($choices));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
|
||||
*/
|
||||
|
Reference in New Issue
Block a user