diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index 9eff215e34..15400da174 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -274,7 +274,7 @@ class EntityTypeTest extends TypeTestCase $field->submit(null); $this->assertNull($field->getData()); - $this->assertNull($field->getViewData()); + $this->assertSame('', $field->getViewData(), 'View data is always a string'); } public function testSubmitSingleNonExpandedNull() diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index aeebd1c506..3fa2d63601 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -21,11 +21,19 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { +<<<<<<< HEAD "symfony/stopwatch": "~2.8|~3.0", "symfony/dependency-injection": "~2.8|~3.0", "symfony/form": "~3.0", "symfony/http-kernel": "~2.8|~3.0", "symfony/property-access": "~2.8|~3.0", +======= + "symfony/stopwatch": "~2.2|~3.0.0", + "symfony/dependency-injection": "~2.2|~3.0.0", + "symfony/form": "~2.8.5|~3.0.5", + "symfony/http-kernel": "~2.2|~3.0.0", + "symfony/property-access": "~2.3|~3.0.0", +>>>>>>> 2.8 "symfony/property-info": "~2.8|3.0", "symfony/security": "~2.8|~3.0", "symfony/expression-language": "~2.8|~3.0", diff --git a/src/Symfony/Component/Form/Extension/Core/DataMapper/CheckboxListMapper.php b/src/Symfony/Component/Form/Extension/Core/DataMapper/CheckboxListMapper.php index b1169ceafa..b85fb0025f 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataMapper/CheckboxListMapper.php +++ b/src/Symfony/Component/Form/Extension/Core/DataMapper/CheckboxListMapper.php @@ -11,9 +11,8 @@ namespace Symfony\Component\Form\Extension\Core\DataMapper; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\DataMapperInterface; -use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * Maps choices to/from checkbox forms. @@ -26,16 +25,6 @@ use Symfony\Component\Form\Exception\TransformationFailedException; */ class CheckboxListMapper implements DataMapperInterface { - /** - * @var ChoiceListInterface - */ - private $choiceList; - - public function __construct(ChoiceListInterface $choiceList) - { - $this->choiceList = $choiceList; - } - /** * {@inheritdoc} */ @@ -46,22 +35,12 @@ class CheckboxListMapper implements DataMapperInterface } if (!is_array($choices)) { - throw new TransformationFailedException('Expected an array.'); - } - - try { - $valueMap = array_flip($this->choiceList->getValuesForChoices($choices)); - } catch (\Exception $e) { - throw new TransformationFailedException( - 'Can not read the choices from the choice list.', - $e->getCode(), - $e - ); + throw new UnexpectedTypeException($choices, 'array'); } foreach ($checkboxes as $checkbox) { $value = $checkbox->getConfig()->getOption('value'); - $checkbox->setData(isset($valueMap[$value]) ? true : false); + $checkbox->setData(in_array($value, $choices, true)); } } @@ -70,6 +49,10 @@ class CheckboxListMapper implements DataMapperInterface */ public function mapFormsToData($checkboxes, &$choices) { + if (!is_array($choices)) { + throw new UnexpectedTypeException($choices, 'array'); + } + $values = array(); foreach ($checkboxes as $checkbox) { @@ -79,14 +62,6 @@ class CheckboxListMapper implements DataMapperInterface } } - try { - $choices = $this->choiceList->getChoicesForValues($values); - } catch (\Exception $e) { - throw new TransformationFailedException( - 'Can not read the values from the choice list.', - $e->getCode(), - $e - ); - } + $choices = $values; } } diff --git a/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php b/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php index d08a603b5c..6f757c601f 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php +++ b/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Form\Extension\Core\DataMapper; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\DataMapperInterface; +use Symfony\Component\Form\Exception\UnexpectedTypeException; /** * Maps choices to/from radio forms. @@ -25,24 +25,18 @@ use Symfony\Component\Form\DataMapperInterface; */ class RadioListMapper implements DataMapperInterface { - /** - * @var ChoiceListInterface - */ - private $choiceList; - - public function __construct(ChoiceListInterface $choiceList) - { - $this->choiceList = $choiceList; - } - /** * {@inheritdoc} */ - public function mapDataToForms($data, $radios) + public function mapDataToForms($choice, $radios) { + if (!is_string($choice)) { + throw new UnexpectedTypeException($choice, 'string'); + } + foreach ($radios as $radio) { $value = $radio->getConfig()->getOption('value'); - $radio->setData($value === $data ? true : false); + $radio->setData($choice === $value); } } @@ -51,6 +45,10 @@ class RadioListMapper implements DataMapperInterface */ public function mapFormsToData($radios, &$choice) { + if (null !== $choice && !is_string($choice)) { + throw new UnexpectedTypeException($choice, 'null or string'); + } + $choice = null; foreach ($radios as $radio) { @@ -59,8 +57,7 @@ class RadioListMapper implements DataMapperInterface return; } - $value = $radio->getConfig()->getOption('value'); - $choice = current($this->choiceList->getChoicesForValues(array($value))); + $choice = $radio->getConfig()->getOption('value'); return; } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index 6050a430a5..845c238cd4 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -61,9 +61,7 @@ class ChoiceType extends AbstractType $builder->setAttribute('choice_list', $choiceList); if ($options['expanded']) { - $builder->setDataMapper($options['multiple'] - ? new CheckboxListMapper($choiceList) - : new RadioListMapper($choiceList)); + $builder->setDataMapper($options['multiple'] ? new CheckboxListMapper() : new RadioListMapper()); // Initialize all choices before doing the index check below. // This helps in cases where index checks are optimized for non @@ -134,30 +132,13 @@ class ChoiceType extends AbstractType $event->setData($data); }); + } - if (!$options['multiple']) { - // For radio lists, transform empty arrays to null - // This is kind of a hack necessary because the RadioListMapper - // is not invoked for forms without choices - $builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) { - if (array() === $event->getData()) { - $event->setData(null); - } - }); - // For radio lists, pre selection of the choice needs to pre set data - // with the string value so it can be matched in - // {@link \Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper::mapDataToForms()} - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { - $choiceList = $event->getForm()->getConfig()->getAttribute('choice_list'); - $value = current($choiceList->getValuesForChoices(array($event->getData()))); - $event->setData((string) $value); - }); - } - } elseif ($options['multiple']) { - // tag with "multiple" option or list of checkbox inputs $builder->addViewTransformer(new ChoicesToValuesTransformer($choiceList)); } else { - // tag without "multiple" option or list of radio inputs $builder->addViewTransformer(new ChoiceToValueTransformer($choiceList)); } @@ -252,7 +233,11 @@ class ChoiceType extends AbstractType public function configureOptions(OptionsResolver $resolver) { $emptyData = function (Options $options) { - if ($options['multiple'] || $options['expanded']) { + if ($options['expanded'] && !$options['multiple']) { + return; + } + + if ($options['multiple']) { return array(); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index 730164d666..125358949b 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -30,6 +30,20 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase 'n/a' => '', ); + private $booleanChoicesWithNull = array( + 'Yes' => true, + 'No' => false, + 'n/a' => null, + ); + + private $numericChoicesFlipped = array( + 0 => 'Bernhard', + 1 => 'Fabien', + 2 => 'Kris', + 3 => 'Jon', + 4 => 'Roman', + ); + private $objectChoices; protected $groupedChoices = array( @@ -135,6 +149,19 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $this->assertTrue($view->children[2]->vars['checked'], 'Empty value should be pre selected'); } + public function testExpandedChoiceListWithBooleanAndNullValues() + { + $view = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( + 'choices' => $this->booleanChoicesWithNull, + 'choices_as_values' => true, + 'expanded' => true, + ))->createView(); + + $this->assertFalse($view->children[0]->vars['checked'], 'True value should not be pre selected'); + $this->assertFalse($view->children[1]->vars['checked'], 'False value should not be pre selected'); + $this->assertTrue($view->children[2]->vars['checked'], 'Empty value should be pre selected'); + } + public function testExpandedChoiceListWithScalarValuesAndFalseAsPreSetData() { $view = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', false, array( @@ -148,6 +175,19 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $this->assertFalse($view->children[2]->vars['checked'], 'Empty value should not be pre selected'); } + public function testExpandedChoiceListWithBooleanAndNullValuesAndFalseAsPreSetData() + { + $view = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', false, array( + 'choices' => $this->booleanChoicesWithNull, + 'choices_as_values' => true, + 'expanded' => true, + ))->createView(); + + $this->assertFalse($view->children[0]->vars['checked'], 'True value should not be pre selected'); + $this->assertTrue($view->children[1]->vars['checked'], 'False value should be pre selected'); + $this->assertFalse($view->children[2]->vars['checked'], 'Null value should not be pre selected'); + } + public function testPlaceholderPresentOnNonRequiredExpandedSingleChoice() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array( @@ -263,7 +303,7 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $view = $form->createView(); - $this->assertSame('', $view->vars['value'], 'Value should be empty'); + $this->assertSame('', $view->vars['value'], 'Value should be an empty string'); $this->assertSame('1', $view->vars['choices'][0]->value); $this->assertSame('0', $view->vars['choices'][1]->value, 'Choice "false" should have "0" as value'); $this->assertFalse($view->children[1]->vars['checked'], 'Choice "false" should not be selected'); @@ -767,8 +807,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(null); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); $this->assertFalse($form[0]->getData()); @@ -798,8 +838,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(null); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); } @@ -815,8 +855,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(''); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); $this->assertFalse($form[0]->getData()); @@ -846,8 +886,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(''); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); } @@ -863,8 +903,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(false); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); $this->assertFalse($form[0]->getData()); @@ -894,8 +934,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(false); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); } @@ -911,8 +951,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(null); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); $this->assertTrue($form['placeholder']->getData()); @@ -944,8 +984,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(null); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); } @@ -961,8 +1001,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(''); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); $this->assertTrue($form['placeholder']->getData()); @@ -994,8 +1034,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(''); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); } @@ -1011,8 +1051,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(false); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); $this->assertTrue($form['placeholder']->getData()); @@ -1044,8 +1084,8 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(false); $this->assertNull($form->getData()); - $this->assertNull($form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame('', $form->getViewData(), 'View data should always be a string'); + $this->assertSame(array(), $form->getExtraData(), 'ChoiceType is compound when expanded, extra data should always be an array'); $this->assertTrue($form->isSynchronized()); } @@ -1062,7 +1102,7 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $form->submit(''); - $this->assertNull($form->getData()); + $this->assertSame('', $form->getData()); $this->assertTrue($form->isSynchronized()); $this->assertTrue($form[0]->getData());