8000 [Form] Add option widget to ChoiceType · symfony/symfony@bb386ab · GitHub
[go: up one dir, main page]

Skip to content

Commit bb386ab

Browse files
committed
[Form] Add option widget to ChoiceType
1 parent 0bacaba commit bb386ab

File tree

5 files changed

+272
-6
lines changed

5 files changed

+272
-6
lines changed

src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@
3535
{%- endblock textarea_widget -%}
3636

3737
{%- block choice_widget -%}
38-
{% if expanded %}
38+
{% if 'hidden' == widget %}
39+
{{- block('hidden_widget') -}}
40+
{% elseif 'text' == widget %}
41+
{{- block('form_widget_simple') -}}
42+
{% elseif expanded %}
3943
{{- block('choice_widget_expanded') -}}
4044
{% else %}
4145
{{- block('choice_widget_collapsed') -}}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13+
14+
use Symfony\Component\Form\DataTransformerInterface;
15+
use Symfony\Component\Form\Exception\TransformationFailedException;
16+
17+
/**
18+
* Converts an array of values to a string with multiple values separated by a delimiter.
19+
*
20+
* @author Bilal Amarni <bilal.amarni@gmail.com>
21+
*/
22+
class ValuesToStringTransformer implements DataTransformerInterface
23+
{
24+
/**
25+
* @var string
26+
*/
27+
private $delimiter;
28+
29+
/**
30+
* @var bool
31+
*/
32+
private $trim;
33+
34+
/**
35+
* @param string $delimiter
36+
* @param bool $trim
37+
*/
38+
public function __construct($delimiter, $trim)
39+
{
40+
$this->delimiter = $delimiter;
41+
$this->trim = $trim;
42+
}
43+
44+
/**
45+
* @param array $array
46+
*
47+
* @return string
48+
*
49+
* @throws UnexpectedTypeException if the given value is not an array
50+
*/
51+
public function transform($array)
52+
{
53+
if (null === $array) {
54+
return '';
55+
}
56+
57+
if (!is_array($array)) {
58+
throw new TransformationFailedException('Expected an array');
59+
}
60+
61+
return implode($this->delimiter, $array);
62+
}
63+
64+
/**
65+
* @param string $string
66+
*
67+
* @return array
68+
*
69+
* @throws UnexpectedTypeException if the given value is not a string
70+
*/
71+
public function reverseTransform($string)
72+
{
73+
if (empty($string)) {
74+
return array();
75+
}
76+
77+
if (!is_string($string)) {
78+
throw new TransformationFailedException('Expected a string');
79+
}
80+
81+
$values = explode($this->delimiter, $string);
82+
83+
if ($this->trim) {
84+
$values = array_map('trim', $values);
85+
}
86+
87+
return $values;
88+
}
89+
}

src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
3232
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
3333
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
34+
use Symfony\Component\Form\Extension\Core\DataTransformer\ValuesToStringTransformer;
3435
use Symfony\Component\OptionsResolver\Options;
3536
use Symfony\Component\OptionsResolver\OptionsResolver;
3637

@@ -60,7 +61,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
6061
$choiceList = $this->createChoiceList($options);
6162
$builder->setAttribute('choice_list', $choiceList);
6263

63-
if ($options['expanded']) {
64+
if ($options['expanded'] && !in_array($options['widget'], array('text', 'hidden'))) {
6465
$builder->setDataMapper($options['multiple']
6566
? new CheckboxListMapper($choiceList)
6667
: new RadioListMapper($choiceList));
@@ -146,10 +147,15 @@ public function buildForm(FormBuilderInterface $builder, array $options)
146147
});
147148
}
148149
} elseif ($options['multiple']) {
149-
// <select> tag with "multiple" option
150+
// "select", "text" or "hidden" widget with "multiple" option
150151
$builder->addViewTransformer(new ChoicesToValuesTransformer($choiceList));
152+
153+
// for "text" / "hidden" widget, view data uses a delimiter
154+
if (in_array($options['widget'], array('text', 'hidden'))) {
155+
$builder->addViewTransformer(new ValuesToStringTransformer($options['delimiter'], $options['trim']));
156+
}
151157
} else {
152-
// <select> tag without "multiple" option
158+
// "select", "text" or "hidden" tag without "multiple" option
153159
$builder->addViewTransformer(new ChoiceToValueTransformer($choiceList));
154160
}
155161

@@ -179,15 +185,20 @@ public function buildView(FormView $view, FormInterface $form, array $options)
179185
: $this->createChoiceListView($choiceList, $options);
180186

181187
$view->vars = array_replace($view->vars, array(
188+
'widget' => $options['widget'],
182189
'multiple' => $options['multiple'],
183-
'expanded' => $options['expanded'],
190+
'expanded' => $options['expanded'], // BC
184191
'preferred_choices' => $choiceListView->preferredChoices,
185192
'choices' => $choiceListView->choices,
186193
'separator' => '-------------------',
187194
'placeholder' => null,
188195
'choice_translation_domain' => $choiceTranslationDomain,
189196
));
190197

198+
if (in_array($options['widget'], array('text', 'hidden'))) {
199+
return;
200+
}
201+
191202
// The decision, whether a choice is selected, is potentially done
192203
// thousand of times during the rendering of a template. Provide a
193204
// closure here that is optimized for the value of the form, to
@@ -226,6 +237,10 @@ public function buildView(FormView $view, FormInterface $form, array $options)
226237
*/
227238
public function finishView(FormView $view, FormInterface $form, array $options)
228239
{
240+
if (in_array($options['widget'], array('text', 'hidden'))) {
241+
return;
242+
}
243+
229244
if ($options['expanded']) {
230245
// Radio buttons should have the same name as the parent
231246
$childName = $view->vars['full_name'];
@@ -302,9 +317,30 @@ public function configureOptions(OptionsResolver $resolver)
302317
return $choiceTranslationDomain;
303318
};
304319

320+
$multipleNormalizer = function (Options $options, $multiple) {
321+
if (in_array($options['widget'], array('radio', 'checkbox'))) {
322+
return 'checkbox' == $options['widget'];
323+
}
324+
325+
return $multiple;
326+
};
327+
328+
$expandedNomalizer = function (Options $options, $expanded) {
329+
if (null !== $expanded) {
330+
@trigger_error('The "expanded" option is deprecated since version 3.1 and will be removed in 4.0. You should use "widget" instead.', E_USER_DEPRECATED);
331+
} else {
332+
$expanded = false;
333+
}
334+
335+
return in_array($options['widget'], array('radio', 'checkbox')) ?: $expanded;
336+
};
337+
305338
$resolver->setDefaults(array(
339+
'widget' => null,
306340
'multiple' => false,
307-
'expanded' => false,
341+
'delimiter' => ',',
342+
'expanded' => null, // deprecated
343+
'choice_list' => null, // deprecated
308344
'choices' => array(),
309345
'choices_as_values' => null, // deprecated since 3.1
310346
'choice_loader' => null,
@@ -325,6 +361,8 @@ public function configureOptions(OptionsResolver $resolver)
325361
'choice_translation_domain' => true,
326362
));
327363

364+
$resolver->setNormalizer('expanded', $expandedNomalizer);
365+
$resolver->setNormalizer('multiple', $multipleNormalizer);
328366
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
329367
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
330368
$resolver->setNormalizer('choices_as_values', $choicesAsValuesNormalizer);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13+
14+
use Symfony\Component\Form\Extension\Core\DataTransformer\ValuesToStringTransformer;
15+
16+
class ValuesToStringTransformerTest extends \PHPUnit_Framework_TestCase
17+
{
18+
private $transformer;
19+
20+
protected function setUp()
21+
{
22+
$this->transformer = new ValuesToStringTransformer(',', true);
23+
}
24+
25+
protected function tearDown()
26+
{
27+
$this->transformer = null;
28+
}
29+
30+
public function testTransform()
31+
{
32+
$output = 'a,b,c';
33+
34+
$this->assertSame($output, $this->transformer->transform(array('a', 'b', 'c')));
35+
}
36+
37+
public function testTransformNull()
38+
{
39+
$this->assertSame('', $this->transformer->transform(null));
40+
}
41+
42+
/**
43+
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
44+
*/
45+
public function testReverseTransformRequiresAnArray()
46+
{
47+
$this->transformer->transform('a, b, c');
48+
}
49+
50+
public function testReverseTransform()
51+
{
52+
$input = 'a, b ,c ';
53+
54+
$this->assertSame(array('a', 'b', 'c'), $this->transformer->reverseTransform($input));
55+
}
56+
57+
public function testReverseTransformEmpty()
58+
{
59+
$input = '';
60+
61+
$this->assertSame(array(), $this->transformer->reverseTransform($input));
62+
}
63+
64+
/**
65+
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
66+
*/
67+
public function testReverseTransformRequiresAString()
68+
{
69+
$this->transformer->reverseTransform(array('a', 'b', 'c'));
70+
}
71+
}

src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,4 +1505,68 @@ public function testCustomChoiceTypeDoesNotInheritChoiceLabels()
15051505
// In this case the 'choice_label' closure returns null and not the closure from the first choice type.
15061506
$this->assertNull($form->get('subChoice')->getConfig()->getOption('choice_label'));
15071507
}
1508+
1509+
/**
1510+
* @dataProvider simpleWidgetsProvider
1511+
*/
1512+
public function testSubmitChoicesWithSimpleWidgets($widget)
1513+
{
1514+
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array(
1515+
'widget' => $widget,
1516+
'multiple' => false,
1517+
'choices' => $this->choices,
1518+
'choices_as_values' => true,
1519+
));
1520+
1521+
$form->submit('b');
1522+
1523+
$this->assertEquals('b', $form->getData());
1524+
$this->assertEquals('b', $form->getViewData());
1525+
}
1526+
1527+
/**
1528+
* @dataProvider simpleWidgetsProvider
1529+
*/
1530+
public function testSubmitMultipleChoicesWithSimpleWidgets($widget)
1531+
{
1532+
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array(
1533+
'widget' => $widget,
1534+
'multiple' => true,
1535+
'choices' => $this->choices,
1536+
'choices_as_values' => true,
1537+
));
1538+
1539+
$form->submit('a,b');
1540+
1541+
$this->assertEquals(array('a', 'b'), $form->getData());
1542+
$this->assertEquals('a,b', $form->getViewData());
1543+
}
1544+
1545+
/**
1546+
* @dataProvider simpleWidgetsProvider
1547+
*/
1548+
public function testSubmitMultipleChoicesDelimiterAndTrimWithSimpleWidgets($widget)
1549+
{
1550+
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array(
1551+
'widget' => $widget,
1552+
'multiple' => true,
1553+
'delimiter' => '|',
1554+
'trim' => true,
1555+
'choices' => $this->choices,
1556+
'choices_as_values' => true,
1557+
));
1558+
1559+
$form->submit('a| b ');
1560+
1561+
$this->assertEquals(array('a', 'b'), $form->getData());
1562+
$this->assertEquals('a|b', $form->getViewData());
1563+
}
1564+
1565+
public function simpleWidgetsProvider()
1566+
{
1567+
return array(
1568+
array('text'),
1569+
array('hidden'),
1570+
);
1571+
}
15081572
}

0 commit comments

Comments
 (0)
0