Skip to content

Commit

Permalink
[Form] ChoiceField now accepts closures in the 'choices' option
Browse files Browse the repository at this point in the history
  • Loading branch information
Bernhard Schussek authored and fabpot committed Jan 28, 2011
1 parent 9e6e95d commit ce61baf
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 21 deletions.
60 changes: 51 additions & 9 deletions src/Symfony/Component/Form/ChoiceField.php
Expand Up @@ -40,15 +40,26 @@ 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');
$this->addOption('preferred_choices', array());
$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'))) {
Expand All @@ -62,7 +73,7 @@ protected function configure()
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]));
Expand All @@ -76,8 +87,6 @@ protected function configure()
} else {
$this->setFieldMode(self::FIELD);
}

parent::configure();
}

public function getName()
Expand All @@ -95,19 +104,52 @@ public function getName()
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;
}
Expand Down Expand Up @@ -183,7 +225,7 @@ protected function transform($value)
{
if ($this->isExpanded()) {
$value = parent::transform($value);
$choices = $this->getOption('choices');
$choices = $this->getInitializedChoices();

foreach ($choices as $choice => $_) {
$choices[$choice] = $this->isMultipleChoice()
Expand Down
62 changes: 50 additions & 12 deletions tests/Symfony/Tests/Component/Form/ChoiceFieldTest.php
Expand Up @@ -67,12 +67,35 @@ public function testConfigurePreferredChoicesWithNonArray()
));
}

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');
Expand All @@ -81,12 +104,15 @@ public function testBindSingleNonExpanded()
$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'));
Expand All @@ -95,12 +121,15 @@ public function testBindMultipleNonExpanded()
$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');
Expand All @@ -119,12 +148,15 @@ public function testBindSingleExpanded()
$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');
Expand All @@ -143,12 +175,15 @@ public function testBindSingleExpandedNumericChoices()
$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'));
Expand All @@ -167,12 +202,15 @@ public function testBindMultipleExpanded()
$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));
Expand Down

0 comments on commit ce61baf

Please sign in to comment.