[Form] Fixed handling of expanded choice lists, checkboxes and radio buttons with empty values ("")

This commit is contained in:
Bernhard Schussek 2012-04-10 11:51:28 +02:00
parent 07e261ea9e
commit 26451201e0
11 changed files with 306 additions and 153 deletions

View File

@ -167,17 +167,6 @@ UPGRADE FROM 2.0 to 2.1
colons and underscores, you can restore the old behavior by setting the
`index_strategy` choice field option to `ChoiceList::COPY_CHOICE`.
* The strategy for generating the `value` HTML attribute for choices in a
choice field has changed.
Instead of using the choice value, a generated integer is now stored. Again,
take care if your JavaScript reads this value. If your choice field is a
non-expanded single-choice field, or if the choices are guaranteed not to
contain the empty string '' (which is the case when you added it manually
or when the field is a single-choice field and is not required), you can
restore the old behavior by setting the `value_strategy` choice field option
to `ChoiceList::COPY_CHOICE`.
* In the choice field type's template, the structure of the `choices` variable
has changed.

View File

@ -442,8 +442,8 @@ class EntityTypeTest extends TypeTestCase
$this->assertSame($entity2, $field->getData());
$this->assertFalse($field['1']->getData());
$this->assertTrue($field['2']->getData());
$this->assertSame('', $field['1']->getClientData());
$this->assertSame('1', $field['2']->getClientData());
$this->assertNull($field['1']->getClientData());
$this->assertSame('2', $field['2']->getClientData());
}
public function testSubmitMultipleExpanded()
@ -462,7 +462,7 @@ class EntityTypeTest extends TypeTestCase
'property' => 'name',
));
$field->bind(array('1' => '1', '3' => '3'));
$field->bind(array('1', '3'));
$expected = new ArrayCollection(array($entity1, $entity3));
@ -472,8 +472,8 @@ class EntityTypeTest extends TypeTestCase
$this->assertFalse($field['2']->getData());
$this->assertTrue($field['3']->getData());
$this->assertSame('1', $field['1']->getClientData());
$this->assertSame('', $field['2']->getClientData());
$this->assertSame('1', $field['3']->getClientData());
$this->assertNull($field['2']->getClientData());
$this->assertSame('3', $field['3']->getClientData());
}
public function testOverrideChoices()

View File

@ -22,6 +22,22 @@ use Symfony\Component\Form\Exception\UnexpectedTypeException;
*/
class BooleanToStringTransformer implements DataTransformerInterface
{
/**
* The value emitted upon transform if the input is true
* @var string
*/
private $trueValue;
/**
* Sets the value emitted upon transform if the input is true.
*
* @param string $trueValue
*/
public function __construct($trueValue)
{
$this->trueValue = $trueValue;
}
/**
* Transforms a Boolean into a string.
*
@ -34,14 +50,14 @@ class BooleanToStringTransformer implements DataTransformerInterface
public function transform($value)
{
if (null === $value) {
return '';
return null;
}
if (!is_bool($value)) {
throw new UnexpectedTypeException($value, 'Boolean');
}
return true === $value ? '1' : '';
return true === $value ? $this->trueValue : null;
}
/**
@ -63,7 +79,7 @@ class BooleanToStringTransformer implements DataTransformerInterface
throw new UnexpectedTypeException($value, 'string');
}
return '' !== $value;
return true;
}
}

View File

@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Extension\Core\EventListener;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
/**
* Takes care of converting the input from a list of checkboxes to a correctly
* indexed array.
*
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class FixCheckboxInputListener implements EventSubscriberInterface
{
private $choiceList;
/**
* Constructor.
*
* @param ChoiceListInterface $choiceList
*/
public function __construct(ChoiceListInterface $choiceList)
{
$this->choiceList = $choiceList;
}
public function onBindClientData(FilterDataEvent $event)
{
$values = (array) $event->getData();
$indices = $this->choiceList->getIndicesForValues($values);
$event->setData(array_combine($indices, $values));
}
static public function getSubscribedEvents()
{
return array(FormEvents::BIND_CLIENT_DATA => 'onBindClientData');
}
}

View File

@ -25,7 +25,7 @@ class CheckboxType extends AbstractType
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->appendClientTransformer(new BooleanToStringTransformer())
->appendClientTransformer(new BooleanToStringTransformer($options['value']))
->setAttribute('value', $options['value'])
;
}
@ -37,7 +37,7 @@ class CheckboxType extends AbstractType
{
$view
->set('value', $form->getAttribute('value'))
->set('checked', (Boolean) $form->getClientData())
->set('checked', null !== $form->getClientData())
;
}
@ -48,6 +48,9 @@ class CheckboxType extends AbstractType
{
return array(
'value' => '1',
'empty_data' => function (FormInterface $form, $clientData) {
return $clientData;
},
);
}

View File

@ -14,13 +14,14 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
use Symfony\Component\Form\Extension\Core\EventListener\FixCheckboxInputListener;
use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToBooleanArrayTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
@ -81,7 +82,10 @@ class ChoiceType extends AbstractType
if ($options['expanded']) {
if ($options['multiple']) {
$builder->appendClientTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list']));
$builder
->appendClientTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list']))
->addEventSubscriber(new FixCheckboxInputListener($options['choice_list']), 10)
;
} else {
$builder
->appendClientTransformer(new ChoiceToBooleanArrayTransformer($options['choice_list']))
@ -155,7 +159,7 @@ class ChoiceType extends AbstractType
'choice_list' => null,
'choices' => null,
'preferred_choices' => array(),
'value_strategy' => ChoiceList::GENERATE,
'value_strategy' => ChoiceList::COPY_CHOICE,
'index_strategy' => ChoiceList::GENERATE,
'empty_data' => $multiple || $expanded ? array() : '',
'empty_value' => $multiple || $expanded || !isset($options['empty_value']) ? null : '',

View File

@ -470,7 +470,11 @@ class Form implements \IteratorAggregate, FormInterface
return $this;
}
if (is_scalar($clientData) || null === $clientData) {
// Don't convert NULL to a string here in order to determine later
// whether an empty value has been submitted or whether no value has
// been submitted at all. This is important for processing checkboxes
// and radio buttons with empty values.
if (is_scalar($clientData)) {
$clientData = (string) $clientData;
}
@ -522,11 +526,13 @@ class Form implements \IteratorAggregate, FormInterface
}
if (null === $clientData || '' === $clientData) {
$clientData = $this->emptyData;
$emptyData = $this->emptyData;
if ($clientData instanceof \Closure) {
$clientData = $clientData($this);
if ($emptyData instanceof \Closure) {
$emptyData = $emptyData($this, $clientData);
}
$clientData = $emptyData;
}
// Merge form data from children into existing client data

View File

@ -330,8 +330,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@name="name"]
[@required="required"]
[
./option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
'
@ -352,9 +352,9 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@name="name"]
[@required="required"]
[
./option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
/following-sibling::option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
]
[count(./option)=3]
'
@ -376,8 +376,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@name="name"]
[@required="required"]
[
./option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
]
[count(./option)=2]
'
@ -398,9 +398,9 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@name="name"]
[@required="required"]
[
./option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@disabled="disabled"][not(@selected)][.=""]
/following-sibling::option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
]
[count(./option)=3]
'
@ -438,8 +438,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[not(@required)]
[
./option[@value=""][.="[trans][/trans]"]
/following-sibling::option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
@ -461,8 +461,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[not(@required)]
[
./option[@value=""][.="[trans][/trans]"]
/following-sibling::option[@value="0"][not(@selected)][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
@ -485,8 +485,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[not(@required)]
[
./option[@value=""][not(@selected)][.="[trans]Select&Anything&Not&Me[/trans]"]
/following-sibling::option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
@ -509,8 +509,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@required="required"]
[
./option[@value=""][.="[trans]Test&Me[/trans]"]
/following-sibling::option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
@ -532,8 +532,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@required="required"]
[
./option[@value=""][.="[trans][/trans]"]
/following-sibling::option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
@ -556,13 +556,13 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@name="name"]
[./optgroup[@label="[trans]Group&1[/trans]"]
[
./option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
]
[./optgroup[@label="[trans]Group&2[/trans]"]
[./option[@value="2"][not(@selected)][.="[trans]Choice&C[/trans]"]]
[./option[@value="&c"][not(@selected)][.="[trans]Choice&C[/trans]"]]
[count(./option)=1]
]
[count(./optgroup)=2]
@ -583,8 +583,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@name="name[]"]
[@multiple="multiple"]
[
./option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
'
@ -605,8 +605,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@name="name[]"]
[@multiple="multiple"]
[
./option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
'
@ -627,8 +627,8 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
[@name="name[]"]
[@multiple="multiple"]
[
./option[@value="0"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="1"][not(@selected)][.="[trans]Choice&B[/trans]"]
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
'
@ -646,9 +646,9 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./input[@type="radio"][@name="name"][@id="name_0"][@value="0"][@checked]
./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="1"][not(@checked)]
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
]
[count(./input)=2]

View File

@ -15,11 +15,13 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\BooleanToStringTransfo
class BooleanToStringTransformerTest extends \PHPUnit_Framework_TestCase
{
const TRUE_VALUE = '1';
protected $transformer;
protected function setUp()
{
$this->transformer = new BooleanToStringTransformer();
$this->transformer = new BooleanToStringTransformer(self::TRUE_VALUE);
}
protected function tearDown()
@ -29,9 +31,9 @@ class BooleanToStringTransformerTest extends \PHPUnit_Framework_TestCase
public function testTransform()
{
$this->assertEquals('1', $this->transformer->transform(true));
$this->assertEquals('', $this->transformer->transform(false));
$this->assertSame('', $this->transformer->transform(null));
$this->assertEquals(self::TRUE_VALUE, $this->transformer->transform(true));
$this->assertNull($this->transformer->transform(false));
$this->assertNull($this->transformer->transform(null));
}
public function testTransformExpectsBoolean()
@ -50,9 +52,9 @@ class BooleanToStringTransformerTest extends \PHPUnit_Framework_TestCase
public function testReverseTransform()
{
$this->assertTrue($this->transformer->reverseTransform('1'));
$this->assertTrue($this->transformer->reverseTransform('0'));
$this->assertFalse($this->transformer->reverseTransform(''));
$this->assertTrue($this->transformer->reverseTransform(self::TRUE_VALUE));
$this->assertTrue($this->transformer->reverseTransform('foobar'));
$this->assertTrue($this->transformer->reverseTransform(''));
$this->assertFalse($this->transformer->reverseTransform(null));
}
}

View File

@ -32,6 +32,15 @@ class CheckboxTypeTest extends TypeTestCase
$this->assertTrue($view->get('checked'));
}
public function testCheckedIfDataTrueWithEmptyValue()
{
$form = $this->factory->create('checkbox', null, array('value' => ''));
$form->setData(true);
$view = $form->createView();
$this->assertTrue($view->get('checked'));
}
public function testNotCheckedIfDataFalse()
{
$form = $this->factory->create('checkbox');
@ -41,8 +50,63 @@ class CheckboxTypeTest extends TypeTestCase
$this->assertFalse($view->get('checked'));
}
public function testBindWithValueChecked()
{
$form = $this->factory->create('checkbox', null, array(
'value' => 'foobar',
));
$form->bind('foobar');
$this->assertTrue($form->getData());
$this->assertEquals('foobar', $form->getClientData());
}
public function testBindWithRandomValueChecked()
{
$form = $this->factory->create('checkbox', null, array(
'value' => 'foobar',
));
$form->bind('krixikraxi');
$this->assertTrue($form->getData());
$this->assertEquals('foobar', $form->getClientData());
}
public function testBindWithValueUnchecked()
{
$form = $this->factory->create('checkbox', null, array(
'value' => 'foobar',
));
$form->bind(null);
$this->assertFalse($form->getData());
$this->assertNull($form->getClientData());
}
public function testBindWithEmptyValueChecked()
{
$form = $this->factory->create('checkbox', null, array(
'value' => '',
));
$form->bind('');
$this->assertTrue($form->getData());
$this->assertSame('', $form->getClientData());
}
public function testBindWithEmptyValueUnchecked()
{
$form = $this->factory->create('checkbox', null, array(
'value' => '',
));
$form->bind(null);
$this->assertFalse($form->getData());
$this->assertNull($form->getClientData());
}
/**
* @dataProvider proviceTransformedData
* @dataProvider provideTransformedData
*/
public function testTransformedData($data, $expected)
{
@ -60,7 +124,7 @@ class CheckboxTypeTest extends TypeTestCase
$form = $this->builder
->create('expedited_shipping', 'checkbox')
->prependClientTransformer($transformer)
->prependNormTransformer($transformer)
->getForm();
$form->setData($data);
$view = $form->createView();
@ -68,7 +132,7 @@ class CheckboxTypeTest extends TypeTestCase
$this->assertEquals($expected, $view->get('checked'));
}
public function proviceTransformedData()
public function provideTransformedData()
{
return array(
array('expedited', true),

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
@ -34,14 +36,6 @@ class ChoiceTypeTest extends TypeTestCase
private $objectChoices;
private $stringButNumericChoices = array(
'0' => 'Bernhard',
'1' => 'Fabien',
'2' => 'Kris',
'3' => 'Jon',
'4' => 'Roman',
);
protected $groupedChoices = array(
'Symfony' => array(
'a' => 'Bernhard',
@ -183,10 +177,10 @@ class ChoiceTypeTest extends TypeTestCase
'choices' => $this->choices,
));
$form->bind('1');
$form->bind('b');
$this->assertEquals('b', $form->getData());
$this->assertEquals('1', $form->getClientData());
$this->assertEquals('b', $form->getClientData());
}
public function testBindSingleNonExpandedObjectChoices()
@ -220,10 +214,10 @@ class ChoiceTypeTest extends TypeTestCase
'choices' => $this->choices,
));
$form->bind(array('0', '1'));
$form->bind(array('a', 'b'));
$this->assertEquals(array('a', 'b'), $form->getData());
$this->assertEquals(array('0', '1'), $form->getClientData());
$this->assertEquals(array('a', 'b'), $form->getClientData());
}
public function testBindMultipleNonExpandedObjectChoices()
@ -256,7 +250,7 @@ class ChoiceTypeTest extends TypeTestCase
'choices' => $this->choices,
));
$form->bind('1');
$form->bind('b');
$this->assertSame('b', $form->getData());
$this->assertFalse($form[0]->getData());
@ -264,11 +258,34 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertFalse($form[2]->getData());
$this->assertFalse($form[3]->getData());
$this->assertFalse($form[4]->getData());
$this->assertSame('', $form[0]->getClientData());
$this->assertSame('1', $form[1]->getClientData());
$this->assertSame('', $form[2]->getClientData());
$this->assertSame('', $form[3]->getClientData());
$this->assertSame('', $form[4]->getClientData());
$this->assertNull($form[0]->getClientData());
$this->assertSame('b', $form[1]->getClientData());
$this->assertNull($form[2]->getClientData());
$this->assertNull($form[3]->getClientData());
$this->assertNull($form[4]->getClientData());
}
public function testBindSingleExpandedNothingChecked()
{
$form = $this->factory->create('choice', null, array(
'multiple' => false,
'expanded' => true,
'choices' => $this->choices,
));
$form->bind(null);
$this->assertSame(null, $form->getData());
$this->assertFalse($form[0]->getData());
$this->assertFalse($form[1]->getData());
$this->assertFalse($form[2]->getData());
$this->assertFalse($form[3]->getData());
$this->assertFalse($form[4]->getData());
$this->assertNull($form[0]->getClientData());
$this->assertNull($form[1]->getClientData());
$this->assertNull($form[2]->getClientData());
$this->assertNull($form[3]->getClientData());
$this->assertNull($form[4]->getClientData());
}
public function testBindSingleExpandedWithFalseDoesNotHaveExtraFields()
@ -292,17 +309,17 @@ class ChoiceTypeTest extends TypeTestCase
'expanded' => true,
'choices' => array(
'' => 'Empty',
'1' => 'Not empty',
1 => 'Not empty',
),
));
$form->bind('0');
$form->bind('');
$this->assertNull($form->getData());
$this->assertTrue($form[0]->getData());
$this->assertFalse($form[1]->getData());
$this->assertSame('1', $form[0]->getClientData());
$this->assertSame('', $form[1]->getClientData());
$this->assertSame('', $form[0]->getClientData());
$this->assertNull($form[1]->getClientData());
}
public function testBindSingleExpandedObjectChoices()
@ -329,11 +346,11 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertFalse($form[2]->getData());
$this->assertFalse($form[3]->getData());
$this->assertFalse($form[4]->getData());
$this->assertSame('', $form[0]->getClientData());
$this->assertSame('1', $form[1]->getClientData());
$this->assertSame('', $form[2]->getClientData());
$this->assertSame('', $form[3]->getClientData());
$this->assertSame('', $form[4]->getClientData());
$this->assertNull($form[0]->getClientData());
$this->assertSame('2', $form[1]->getClientData());
$this->assertNull($form[2]->getClientData());
$this->assertNull($form[3]->getClientData());
$this->assertNull($form[4]->getClientData());
}
public function testBindSingleExpandedNumericChoices()
@ -352,34 +369,11 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertFalse($form[2]->getData());
$this->assertFalse($form[3]->getData());
$this->assertFalse($form[4]->getData());
$this->assertSame('', $form[0]->getClientData());
$this->assertNull($form[0]->getClientData());
$this->assertSame('1', $form[1]->getClientData());
$this->assertSame('', $form[2]->getClientData());
$this->assertSame('', $form[3]->getClientData());
$this->assertSame('', $form[4]->getClientData());
}
public function testBindSingleExpandedStringsButNumericChoices()
{
$form = $this->factory->create('choice', null, array(
'multiple' => false,
'expanded' => true,
'choices' => $this->stringButNumericChoices,
));
$form->bind('1');
$this->assertSame(1, $form->getData());
$this->assertFalse($form[0]->getData());
$this->assertTrue($form[1]->getData());
$this->assertFalse($form[2]->getData());
$this->assertFalse($form[3]->getData());
$this->assertFalse($form[4]->getData());
$this->assertSame('', $form[0]->getClientData());
$this->assertSame('1', $form[1]->getClientData());
$this->assertSame('', $form[2]->getClientData());
$this->assertSame('', $form[3]->getClientData());
$this->assertSame('', $form[4]->getClientData());
$this->assertNull($form[2]->getClientData());
$this->assertNull($form[3]->getClientData());
$this->assertNull($form[4]->getClientData());
}
public function testBindMultipleExpanded()
@ -390,19 +384,43 @@ class ChoiceTypeTest extends TypeTestCase
'choices' => $this->choices,
));
$form->bind(array(0 => 'a', 1 => 'b'));
$form->bind(array('a', 'c'));
$this->assertSame(array(0 => 'a', 1 => 'b'), $form->getData());
$this->assertSame(array('a', 'c'), $form->getData());
$this->assertTrue($form[0]->getData());
$this->assertTrue($form[1]->getData());
$this->assertFalse($form[2]->getData());
$this->assertFalse($form[1]->getData());
$this->assertTrue($form[2]->getData());
$this->assertFalse($form[3]->getData());
$this->assertFalse($form[4]->getData());
$this->assertSame('1', $form[0]->getClientData());
$this->assertSame('1', $form[1]->getClientData());
$this->assertSame('', $form[2]->getClientData());
$this->assertSame('', $form[3]->getClientData());
$this->assertSame('', $form[4]->getClientData());
$this->assertSame('a', $form[0]->getClientData());
$this->assertNull($form[1]->getClientData());
$this->assertSame('c', $form[2]->getClientData());
$this->assertNull($form[3]->getClientData());
$this->assertNull($form[4]->getClientData());
}
public function testBindMultipleExpandedWithEmptyField()
{
$form = $this->factory->create('choice', null, array(
'multiple' => true,
'expanded' => true,
'choices' => array(
'' => 'Empty',
1 => 'Not Empty',
2 => 'Not Empty 2',
),
'value_strategy' => ChoiceList::COPY_CHOICE,
));
$form->bind(array('', '2'));
$this->assertSame(array('', 2), $form->getData());
$this->assertTrue($form[0]->getData());
$this->assertFalse($form[1]->getData());
$this->assertTrue($form[2]->getData());
$this->assertSame('', $form[0]->getClientData());
$this->assertNull($form[1]->getClientData());
$this->assertSame('2', $form[2]->getClientData());
}
public function testBindMultipleExpandedObjectChoices()
@ -421,7 +439,7 @@ class ChoiceTypeTest extends TypeTestCase
),
));
$form->bind(array(0 => '1', 1 => '2'));
$form->bind(array('1', '2'));
$this->assertSame(array($this->objectChoices[0], $this->objectChoices[1]), $form->getData());
$this->assertTrue($form[0]->getData());
@ -430,10 +448,10 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertFalse($form[3]->getData());
$this->assertFalse($form[4]->getData());
$this->assertSame('1', $form[0]->getClientData());
$this->assertSame('1', $form[1]->getClientData());
$this->assertSame('', $form[2]->getClientData());
$this->assertSame('', $form[3]->getClientData());
$this->assertSame('', $form[4]->getClientData());
$this->assertSame('2', $form[1]->getClientData());
$this->assertNull($form[2]->getClientData());
$this->assertNull($form[3]->getClientData());
$this->assertNull($form[4]->getClientData());
}
public function testBindMultipleExpandedNumericChoices()
@ -444,7 +462,7 @@ class ChoiceTypeTest extends TypeTestCase
'choices' => $this->numericChoices,
));
$form->bind(array(1 => '1', 2 => '2'));
$form->bind(array('1', '2'));
$this->assertSame(array(1, 2), $form->getData());
$this->assertFalse($form[0]->getData());
@ -452,11 +470,11 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertTrue($form[2]->getData());
$this->assertFalse($form[3]->getData());
$this->assertFalse($form[4]->getData());
$this->assertSame('', $form[0]->getClientData());
$this->assertNull($form[0]->getClientData());
$this->assertSame('1', $form[1]->getClientData());
$this->assertSame('1', $form[2]->getClientData());
$this->assertSame('', $form[3]->getClientData());
$this->assertSame('', $form[4]->getClientData());
$this->assertSame('2', $form[2]->getClientData());
$this->assertNull($form[3]->getClientData());
$this->assertNull($form[4]->getClientData());
}
/*
@ -598,10 +616,10 @@ class ChoiceTypeTest extends TypeTestCase
$view = $form->createView();
$this->assertEquals(array(
new ChoiceView('0', 'A'),
new ChoiceView('1', 'B'),
new ChoiceView('2', 'C'),
new ChoiceView('3', 'D'),
new ChoiceView('a', 'A'),
new ChoiceView('b', 'B'),
new ChoiceView('c', 'C'),
new ChoiceView('d', 'D'),
), $view->get('choices'));
}
@ -615,12 +633,12 @@ class ChoiceTypeTest extends TypeTestCase
$view = $form->createView();
$this->assertEquals(array(
0 => new ChoiceView('0', 'A'),
2 => new ChoiceView('2', 'C'),
0 => new ChoiceView('a', 'A'),
2 => new ChoiceView('c', 'C'),
), $view->get('choices'));
$this->assertEquals(array(
1 => new ChoiceView('1', 'B'),
3 => new ChoiceView('3', 'D'),
1 => new ChoiceView('b', 'B'),
3 => new ChoiceView('d', 'D'),
), $view->get('preferred_choices'));
}
@ -634,19 +652,19 @@ class ChoiceTypeTest extends TypeTestCase
$this->assertEquals(array(
'Symfony' => array(
0 => new ChoiceView('0', 'Bernhard'),
2 => new ChoiceView('2', 'Kris'),
0 => new ChoiceView('a', 'Bernhard'),
2 => new ChoiceView('c', 'Kris'),
),
'Doctrine' => array(
4 => new ChoiceView('4', 'Roman'),
4 => new ChoiceView('e', 'Roman'),
),
), $view->get('choices'));
$this->assertEquals(array(
'Symfony' => array(
1 => new ChoiceView('1', 'Fabien'),
1 => new ChoiceView('b', 'Fabien'),
),
'Doctrine' => array(
3 => new ChoiceView('3', 'Jon'),
3 => new ChoiceView('d', 'Jon'),
),
), $view->get('preferred_choices'));
}