[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(); protected $preferredChoices = array();
/**
* Stores the choices
* You should only access this property through getInitializedChoices()
* @var array
*/
protected $initializedChoices = array();
protected function configure() protected function configure()
{ {
$this->addRequiredOption('choices'); $this->addRequiredOption('choices');
@ -47,8 +54,12 @@ class ChoiceField extends HybridField
$this->addOption('multiple', false); $this->addOption('multiple', false);
$this->addOption('expanded', false); $this->addOption('expanded', false);
if (!is_array($this->getOption('choices'))) { parent::configure();
throw new InvalidOptionsException('The choices option must be an array', array('choices'));
$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'))) { if (!is_array($this->getOption('preferred_choices'))) {
@ -62,7 +73,7 @@ class ChoiceField extends HybridField
if ($this->isExpanded()) { if ($this->isExpanded()) {
$this->setFieldMode(self::GROUP); $this->setFieldMode(self::GROUP);
$choices = $this->getOption('choices'); $choices = $this->getInitializedChoices();
foreach ($this->preferredChoices as $choice => $_) { foreach ($this->preferredChoices as $choice => $_) {
$this->add($this->newChoiceField($choice, $choices[$choice])); $this->add($this->newChoiceField($choice, $choices[$choice]));
@ -76,8 +87,6 @@ class ChoiceField extends HybridField
} else { } else {
$this->setFieldMode(self::FIELD); $this->setFieldMode(self::FIELD);
} }
parent::configure();
} }
public function getName() public function getName()
@ -95,19 +104,52 @@ class ChoiceField extends HybridField
return $name; 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() public function getPreferredChoices()
{ {
return array_intersect_key($this->getOption('choices'), $this->preferredChoices); return array_intersect_key($this->getInitializedChoices(), $this->preferredChoices);
} }
public function getOtherChoices() public function getOtherChoices()
{ {
return array_diff_key($this->getOption('choices'), $this->preferredChoices); return array_diff_key($this->getInitializedChoices(), $this->preferredChoices);
} }
public function getLabel($choice) public function getLabel($choice)
{ {
$choices = $this->getOption('choices'); $choices = $this->getInitializedChoices();
return isset($choices[$choice]) ? $choices[$choice] : null; return isset($choices[$choice]) ? $choices[$choice] : null;
} }
@ -183,7 +225,7 @@ class ChoiceField extends HybridField
{ {
if ($this->isExpanded()) { if ($this->isExpanded()) {
$value = parent::transform($value); $value = parent::transform($value);
$choices = $this->getOption('choices'); $choices = $this->getInitializedChoices();
foreach ($choices as $choice => $_) { foreach ($choices as $choice => $_) {
$choices[$choice] = $this->isMultipleChoice() $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( $field = new ChoiceField('name', array(
'multiple' => false, 'multiple' => false,
'expanded' => false, 'expanded' => false,
'choices' => $this->choices, 'choices' => $choices,
)); ));
$field->bind('b'); $field->bind('b');
@ -81,12 +104,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('b', $field->getDisplayedData()); $this->assertEquals('b', $field->getDisplayedData());
} }
public function testBindMultipleNonExpanded() /**
* @dataProvider getChoicesVariants
*/
public function testBindMultipleNonExpanded($choices)
{ {
$field = new ChoiceField('name', array( $field = new ChoiceField('name', array(
'multiple' => true, 'multiple' => true,
'expanded' => false, 'expanded' => false,
'choices' => $this->choices, 'choices' => $choices,
)); ));
$field->bind(array('a', 'b')); $field->bind(array('a', 'b'));
@ -95,12 +121,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array('a', 'b'), $field->getDisplayedData()); $this->assertEquals(array('a', 'b'), $field->getDisplayedData());
} }
public function testBindSingleExpanded() /**
* @dataProvider getChoicesVariants
*/
public function testBindSingleExpanded($choices)
{ {
$field = new ChoiceField('name', array( $field = new ChoiceField('name', array(
'multiple' => false, 'multiple' => false,
'expanded' => true, 'expanded' => true,
'choices' => $this->choices, 'choices' => $choices,
)); ));
$field->bind('b'); $field->bind('b');
@ -119,12 +148,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array('a' => '', 'b' => '1', 'c' => '', 'd' => '', 'e' => ''), $field->getDisplayedData()); $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( $field = new ChoiceField('name', array(
'multiple' => false, 'multiple' => false,
'expanded' => true, 'expanded' => true,
'choices' => $this->numericChoices, 'choices' => $choices,
)); ));
$field->bind('1'); $field->bind('1');
@ -143,12 +175,15 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
$this->assertSame(array(0 => '', 1 => '1', 2 => '', 3 => '', 4 => ''), $field->getDisplayedData()); $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( $field = new ChoiceField('name', array(
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
'choices' => $this->choices, 'choices' => $choices,
)); ));
$field->bind(array('a' => 'a', 'b' => 'b')); $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()); $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( $field = new ChoiceField('name', array(
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
'choices' => $this->numericChoices, 'choices' => $choices,
)); ));
$field->bind(array(1 => 1, 2 => 2)); $field->bind(array(1 => 1, 2 => 2));