[Form] ObjectChoiceList now compares choices by their value, if a value path is given

This commit is contained in:
Bernhard Schussek 2014-03-28 18:03:44 +01:00
parent 3cd1c9cd5b
commit ce0efb189f
4 changed files with 191 additions and 2 deletions

View File

@ -11,6 +11,8 @@ CHANGELOG
* [BC BREAK] added two optional parameters to FormInterface::getErrors() and
changed the method to return a Symfony\Component\Form\FormErrorIterator
instance instead of an array
* ObjectChoiceList now compares choices by their value, if a value path is
given
2.4.0
-----

View File

@ -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

View File

@ -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.
*

View File

@ -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
*/