[Form] Moved option 'empty_value' to ChoiceField. An empty value is displayed if the field is not required.

This commit is contained in:
Bernhard Schussek 2011-01-27 13:04:02 +01:00 committed by Fabien Potencier
parent 34865a3533
commit ebd2ca6cfe
11 changed files with 99 additions and 160 deletions

View File

@ -21,6 +21,9 @@ use Symfony\Component\Form\Exception\InvalidOptionsException;
* * choices: An array of key-value pairs that will represent the choices
* * preferred_choices: An array of choices (by key) that should be displayed
* above all other options in the field
* * empty_value: If set to a non-false value, an "empty" option will
* be added to the top of the countries choices. A
* common value might be "Choose a country". Default: false.
*
* The multiple and expanded options control exactly which HTML element
* that should be used to render this field:
@ -42,10 +45,10 @@ class ChoiceField extends HybridField
/**
* Stores the choices
* You should only access this property through getInitializedChoices()
* You should only access this property through getChoices()
* @var array
*/
protected $initializedChoices = array();
private $choices = array();
protected function configure()
{
@ -53,6 +56,7 @@ class ChoiceField extends HybridField
$this->addOption('preferred_choices', array());
$this->addOption('multiple', false);
$this->addOption('expanded', false);
$this->addOption('empty_value', '');
parent::configure();
@ -73,7 +77,7 @@ class ChoiceField extends HybridField
if ($this->isExpanded()) {
$this->setFieldMode(self::GROUP);
$choices = $this->getInitializedChoices();
$choices = $this->getChoices();
foreach ($this->preferredChoices as $choice => $_) {
$this->add($this->newChoiceField($choice, $choices[$choice]));
@ -113,13 +117,31 @@ class ChoiceField extends HybridField
*/
protected function initializeChoices()
{
$this->initializedChoices = $this->getOption('choices');
if ($this->initializedChoices instanceof \Closure) {
$this->initializedChoices = $this->initializedChoices->__invoke();
if (!$this->choices) {
$this->choices = $this->getInitializedChoices();
}
}
protected function getInitializedChoices()
{
$choices = $this->getOption('choices');
if ($choices instanceof \Closure) {
$choices = $choices->__invoke();
}
// TESTME
if (!is_array($choices)) {
throw new InvalidOptionsException('The "choices" option must be an array or a closure returning an array', array('choices'));
}
if (!$this->isRequired()) {
$choices = array_merge(array('' => $this->getOption('empty_value')), $choices);
}
return $choices;
}
/**
* Returns the choices
*
@ -128,28 +150,26 @@ class ChoiceField extends HybridField
*
* @return array
*/
protected function getInitializedChoices()
protected function getChoices()
{
if (!$this->initializedChoices) {
$this->initializeChoices();
}
$this->initializeChoices();
return $this->initializedChoices;
return $this->choices;
}
public function getPreferredChoices()
{
return array_intersect_key($this->getInitializedChoices(), $this->preferredChoices);
return array_intersect_key($this->getChoices(), $this->preferredChoices);
}
public function getOtherChoices()
{
return array_diff_key($this->getInitializedChoices(), $this->preferredChoices);
return array_diff_key($this->getChoices(), $this->preferredChoices);
}
public function getLabel($choice)
{
$choices = $this->getInitializedChoices();
$choices = $this->getChoices();
return isset($choices[$choice]) ? $choices[$choice] : null;
}
@ -225,7 +245,7 @@ class ChoiceField extends HybridField
{
if ($this->isExpanded()) {
$value = parent::transform($value);
$choices = $this->getInitializedChoices();
$choices = $this->getChoices();
foreach ($choices as $choice => $_) {
$choices[$choice] = $this->isMultipleChoice()
@ -235,6 +255,7 @@ class ChoiceField extends HybridField
return $choices;
}
return parent::transform($value);
}
@ -265,9 +286,10 @@ class ChoiceField extends HybridField
if ($this->isMultipleChoice()) {
$value = $choices;
} else {
$value = count($choices) > 0 ? current($choices) : null;
$value = count($choices) > 0 ? current($choices) : null;
}
}
return parent::reverseTransform($value);
}
}

View File

@ -16,13 +16,6 @@ use Symfony\Component\Locale\Locale;
/**
* A field for selecting from a list of countries.
*
* In addition to the ChoiceField options, this field has the following
* options:
*
* * empty_value: If set to a non-false value, an "empty" option will
* be added to the top of the countries choices. A
* common value might be "Choose a country". Default: false.
*
* @see Symfony\Component\Form\ChoiceField
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
@ -30,15 +23,7 @@ class CountryField extends ChoiceField
{
protected function configure()
{
$this->addOption('empty_value', false);
$choices = Locale::getDisplayCountries($this->locale);
if (false !== $this->getOption('empty_value')) {
$choices = array('' => $this->getOption('empty_value')) + $choices;
}
$this->addOption('choices', $choices);
$this->addOption('choices', Locale::getDisplayCountries($this->locale));
parent::configure();
}

View File

@ -88,7 +88,6 @@ class Field extends Configurable implements FieldInterface
$this->normalizedData = $this->normalize($this->data);
$this->transformedData = $this->transform($this->normalizedData);
$this->required = $this->getOption('required');
$this->setPropertyPath($this->getOption('property_path'));
}
@ -184,9 +183,14 @@ class Field extends Configurable implements FieldInterface
*/
public function isRequired()
{
if (null === $this->required) {
$this->required = $this->getOption('required');
}
if (null === $this->parent || $this->parent->isRequired()) {
return $this->required;
}
return false;
}

View File

@ -16,13 +16,6 @@ use Symfony\Component\Locale\Locale;
/**
* A field for selecting from a list of languages.
*
* In addition to the ChoiceField options, this field has the following
* options:
*
* * empty_value: If set to a non-false value, an "empty" option will
* be added to the top of the languages choices. A
* common value might be "Choose a language". Default: false.
*
* @see Symfony\Component\Form\ChoiceField
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
@ -33,15 +26,7 @@ class LanguageField extends ChoiceField
*/
protected function configure()
{
$this->addOption('empty_value', false);
$choices = Locale::getDisplayLanguages($this->locale);
if (false !== $this->getOption('empty_value')) {
$choices = array('' => $this->getOption('empty_value')) + $choices;
}
$this->addOption('choices', $choices);
$this->addOption('choices', Locale::getDisplayLanguages($this->locale));
parent::configure();
}

View File

@ -16,13 +16,6 @@ use Symfony\Component\Locale\Locale;
/**
* A field for selecting from a list of locales.
*
* In addition to the ChoiceField options, this field has the following
* options:
*
* * empty_value: If set to a non-false value, an "empty" option will
* be added to the top of the locale choices. A
* common value might be "Choose a locale". Default: false.
*
* @see Symfony\Component\Form\ChoiceField
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
@ -33,15 +26,7 @@ class LocaleField extends ChoiceField
*/
protected function configure()
{
$this->addOption('empty_value', false);
$choices = Locale::getDisplayLocales($this->locale);
if (false !== $this->getOption('empty_value')) {
$choices = array('' => $this->getOption('empty_value')) + $choices;
}
$this->addOption('choices', $choices);
$this->addOption('choices', Locale::getDisplayLocales($this->locale));
parent::configure();
}

View File

@ -14,11 +14,7 @@ namespace Symfony\Component\Form;
/**
* Represents a field where each timezone is broken down by continent.
*
* Available options:
*
* * empty_value: If set to a non-false value, an "empty" option will
* be added to the top of the timezone choices. A
* common value might be "Choose a timezone". Default: false.
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class TimezoneField extends ChoiceField
{
@ -33,15 +29,7 @@ class TimezoneField extends ChoiceField
*/
public function configure()
{
$this->addOption('empty_value', false);
$choices = self::getTimezoneChoices();
if (false !== $this->getOption('empty_value')) {
$choices = array('' => $this->getOption('empty_value')) + $choices;
}
$this->addOption('choices', $choices);
$this->addOption('choices', self::getTimezoneChoices());
parent::configure();
}

View File

@ -87,6 +87,56 @@ class ChoiceFieldTest extends \PHPUnit_Framework_TestCase
);
}
/**
* @expectedException Symfony\Component\Form\Exception\InvalidOptionsException
*/
public function testClosureShouldReturnArray()
{
$field = new ChoiceField('name', array(
'choices' => function () { return 'foobar'; },
));
// trigger closure
$field->getOtherChoices();
}
public function testNonRequiredContainsEmptyField()
{
$field = new ChoiceField('name', array(
'multiple' => false,
'expanded' => false,
'choices' => $this->choices,
'required' => false,
));
$this->assertEquals(array('' => '') + $this->choices, $field->getOtherChoices());
}
public function testRequiredContainsNoEmptyField()
{
$field = new ChoiceField('name', array(
'multiple' => false,
'expanded' => false,
'choices' => $this->choices,
'required' => true,
));
$this->assertEquals($this->choices, $field->getOtherChoices());
}
public function testEmptyValueConfiguresLabelOfEmptyField()
{
$field = new ChoiceField('name', array(
'multiple' => false,
'expanded' => false,
'choices' => $this->choices,
'required' => false,
'empty_value' => 'Foobar',
));
$this->assertEquals(array('' => 'Foobar') + $this->choices, $field->getOtherChoices());
}
/**
* @dataProvider getChoicesVariants
*/

View File

@ -42,24 +42,4 @@ class CountryFieldTest extends \PHPUnit_Framework_TestCase
$this->assertArrayNotHasKey('ZZ', $choices);
}
public function testEmptyValueOption()
{
// empty_value false
$field = new CountryField('country', array('empty_value' => false));
$choices = $field->getOtherChoices();
$this->assertArrayNotHasKey('', $choices);
// empty_value as a blank string
$field = new CountryField('country', array('empty_value' => ''));
$choices = $field->getOtherChoices();
$this->assertArrayHasKey('', $choices);
$this->assertEquals('', $choices['']);
// empty_value as a normal string
$field = new CountryField('country', array('empty_value' => 'Choose a country'));
$choices = $field->getOtherChoices();
$this->assertArrayHasKey('', $choices);
$this->assertEquals('Choose a country', $choices['']);
}
}

View File

@ -42,24 +42,4 @@ class LanguageFieldTest extends \PHPUnit_Framework_TestCase
$this->assertArrayNotHasKey('mul', $choices);
}
public function testEmptyValueOption()
{
// empty_value false
$field = new LanguageField('language', array('empty_value' => false));
$choices = $field->getOtherChoices();
$this->assertArrayNotHasKey('', $choices);
// empty_value as a blank string
$field = new LanguageField('language', array('empty_value' => ''));
$choices = $field->getOtherChoices();
$this->assertArrayHasKey('', $choices);
$this->assertEquals('', $choices['']);
// empty_value as a normal string
$field = new LanguageField('language', array('empty_value' => 'Choose a language'));
$choices = $field->getOtherChoices();
$this->assertArrayHasKey('', $choices);
$this->assertEquals('Choose a language', $choices['']);
}
}

View File

@ -30,24 +30,4 @@ class LocaleFieldTest extends \PHPUnit_Framework_TestCase
$this->assertArrayHasKey('zh_Hans_MO', $choices);
$this->assertEquals('Chinesisch (vereinfacht, Sonderverwaltungszone Macao)', $choices['zh_Hans_MO']);
}
public function testEmptyValueOption()
{
// empty_value false
$field = new LocaleField('language', array('empty_value' => false));
$choices = $field->getOtherChoices();
$this->assertArrayNotHasKey('', $choices);
// empty_value as a blank string
$field = new LocaleField('language', array('empty_value' => ''));
$choices = $field->getOtherChoices();
$this->assertArrayHasKey('', $choices);
$this->assertEquals('', $choices['']);
// empty_value as a normal string
$field = new LocaleField('language', array('empty_value' => 'Choose a locale'));
$choices = $field->getOtherChoices();
$this->assertArrayHasKey('', $choices);
$this->assertEquals('Choose a locale', $choices['']);
}
}

View File

@ -28,24 +28,4 @@ class TimezoneFieldTest extends \PHPUnit_Framework_TestCase
$this->assertArrayHasKey('America/New_York', $choices['America']);
$this->assertEquals('New York', $choices['America']['America/New_York']);
}
public function testEmptyValueOption()
{
// empty_value false
$field = new TimezoneField('timezone', array('empty_value' => false));
$choices = $field->getOtherChoices();
$this->assertArrayNotHasKey('', $choices);
// empty_value as a blank string
$field = new TimezoneField('timezone', array('empty_value' => ''));
$choices = $field->getOtherChoices();
$this->assertArrayHasKey('', $choices);
$this->assertEquals('', $choices['']);
// empty_value as a normal string
$field = new TimezoneField('timezone', array('empty_value' => 'Choose your timezone'));
$choices = $field->getOtherChoices();
$this->assertArrayHasKey('', $choices);
$this->assertEquals('Choose your timezone', $choices['']);
}
}