[Form] ChoiceField now accepts closures in the 'choices' option

This commit is contained in:
Bernhard Schussek 2011-01-26 11:32:37 +01:00 committed by Fabien Potencier
parent 9e6e95d7e4
commit ce61baf717
2 changed files with 101 additions and 21 deletions

View File

@ -40,6 +40,13 @@ class ChoiceField extends HybridField
*/
protected $preferredChoices = array();
/**
* Stores the choices
* You should only access this property through getInitializedChoices()
* @var array
*/
protected $initializedChoices = array();
protected function configure()
{
$this->addRequiredOption('choices');
@ -47,8 +54,12 @@ class ChoiceField extends HybridField
$this->addOption('multiple', false);
$this->addOption('expanded', false);
if (!is_array($this->getOption('choices'))) {
throw new InvalidOptionsException('The choices option must be an array', array('choices'));
parent::configure();
$choices = $this->getOption('choices');
if (!is_array($choices) && !$choices instanceof \Closure) {
throw new InvalidOptionsException('The choices option must be an array or a closure', array('choices'));
}
if (!is_array($this->getOption('preferred_choices'))) {
@ -62,7 +73,7 @@ class ChoiceField extends HybridField
if ($this->isExpanded()) {
$this->setFieldMode(self::GROUP);
$choices = $this->getOption('choices');
$choices = $this->getInitializedChoices();
foreach ($this->preferredChoices as $choice => $_) {
$this->add($this->newChoiceField($choice, $choices[$choice]));
@ -76,8 +87,6 @@ class ChoiceField extends HybridField
} else {
$this->setFieldMode(self::FIELD);
}
parent::configure();
}
public function getName()
@ -95,19 +104,52 @@ class ChoiceField extends HybridField
return $name;
}
/**
* Initializes the choices
*
* If the choices were given as a closure, the closure is executed now.
*
* @return array
*/
protected function initializeChoices()
{
$this->initializedChoices = $this->getOption('choices');
if ($this->initializedChoices instanceof \Closure) {
$this->initializedChoices = $this->initializedChoices->__invoke();
}
}
/**
* Returns the choices
*
* If the choices were given as a closure, the closure is executed on
* the first call of this method.
*
* @return array
*/
protected function getInitializedChoices()
{
if (!$this->initializedChoices) {
$this->initializeChoices();
}
return $this->initializedChoices;
}
public function getPreferredChoices()
{
return array_intersect_key($this->getOption('choices'), $this->preferredChoices);
return array_intersect_key($this->getInitializedChoices(), $this->preferredChoices);
}
public function getOtherChoices()
{
return array_diff_key($this->getOption('choices'), $this->preferredChoices);
return array_diff_key($this->getInitializedChoices(), $this->preferredChoices);
}
public function getLabel($choice)
{
$choices = $this->getOption('choices');
$choices = $this->getInitializedChoices();
return isset($choices[$choice]) ? $choices[$choice] : null;
}
@ -183,7 +225,7 @@ class ChoiceField extends HybridField
{
if ($this->isExpanded()) {
$value = parent::transform($value);
$choices = $this->getOption('choices');
$choices = $this->getInitializedChoices();
foreach ($choices as $choice => $_) {
$choices[$choice] = $this->isMultipleChoice()

View File

@ -67,12 +67,35 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
));
}
public function testBindSingleNonExpanded()
public function getChoicesVariants()
{
$choices = $this->choices;
return array(
array($choices),
array(function () use ($choices) { return $choices; }),
);
}
public function getNumericChoicesVariants()
{
$choices = $this->numericChoices;
return array(
array($choices),
array(function () use ($choices) { return $choices; }),
);
}
/**
* @dataProvider getChoicesVariants
*/
public function testBindSingleNonExpanded($choices)
{
$field = new ChoiceField('name', array(
'multiple' => false,
'expanded' => false,
'choices' => $this->choices,
'choices' => $choices,
));
$field->bind('b');
@ -81,12 +104,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('b', $field->getDisplayedData());
}
public function testBindMultipleNonExpanded()
/**
* @dataProvider getChoicesVariants
*/
public function testBindMultipleNonExpanded($choices)
{
$field = new ChoiceField('name', array(
'multiple' => true,
'expanded' => false,
'choices' => $this->choices,
'choices' => $choices,
));
$field->bind(array('a', 'b'));
@ -95,12 +121,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array('a', 'b'), $field->getDisplayedData());
}
public function testBindSingleExpanded()
/**
* @dataProvider getChoicesVariants
*/
public function testBindSingleExpanded($choices)
{
$field = new ChoiceField('name', array(
'multiple' => false,
'expanded' => true,
'choices' => $this->choices,
'choices' => $choices,
));
$field->bind('b');
@ -119,12 +148,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array('a' => '', 'b' => '1', 'c' => '', 'd' => '', 'e' => ''), $field->getDisplayedData());
}
public function testBindSingleExpandedNumericChoices()
/**
* @dataProvider getNumericChoicesVariants
*/
public function testBindSingleExpandedNumericChoices($choices)
{
$field = new ChoiceField('name', array(
'multiple' => false,
'expanded' => true,
'choices' => $this->numericChoices,
'choices' => $choices,
));
$field->bind('1');
@ -143,12 +175,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array(0 => '', 1 => '1', 2 => '', 3 => '', 4 => ''), $field->getDisplayedData());
}
public function testBindMultipleExpanded()
/**
* @dataProvider getChoicesVariants
*/
public function testBindMultipleExpanded($choices)
{
$field = new ChoiceField('name', array(
'multiple' => true,
'expanded' => true,
'choices' => $this->choices,
'choices' => $choices,
));
$field->bind(array('a' => 'a', 'b' => 'b'));
@ -167,12 +202,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array('a' => '1', 'b' => '1', 'c' => '', 'd' => '', 'e' => ''), $field->getDisplayedData());
}
public function testBindMultipleExpandedNumericChoices()
/**
* @dataProvider getNumericChoicesVariants
*/
public function testBindMultipleExpandedNumericChoices($choices)
{
$field = new ChoiceField('name', array(
'multiple' => true,
'expanded' => true,
'choices' => $this->numericChoices,
'choices' => $choices,
));
$field->bind(array(1 => 1, 2 => 2));