Skip to content

Commit 4748837

Browse files
committed
[Form] added the new ChoiceList class to configure ChoiceType options
1 parent 479b314 commit 4748837

8 files changed

+172
-27
lines changed

reference/forms/types/choice.rst

+9-26
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ To get fancier, use the `group_by`_ option instead.
181181
Field Options
182182
-------------
183183

184+
.. versionadded:: 5.1
185+
186+
The :class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class has
187+
been introduced in Symfony 5.1, to help configuring choices options.
188+
184189
choices
185190
~~~~~~~
186191

@@ -207,35 +212,13 @@ correct types will be assigned to the model.
207212

208213
.. include:: /reference/forms/types/options/choice_attr.rst.inc
209214

210-
.. _reference-form-choice-label:
211-
212-
.. include:: /reference/forms/types/options/choice_label.rst.inc
213-
214-
choice_loader
215-
~~~~~~~~~~~~~
216-
217-
**type**: :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\ChoiceLoaderInterface`
215+
.. _reference-form-choice-loader:
218216

219-
The ``choice_loader`` can be used to only partially load the choices in cases where
220-
a fully-loaded list is not necessary. This is only needed in advanced cases and
221-
would replace the ``choices`` option.
217+
.. include:: /reference/forms/types/options/choice_loader.rst.inc
222218

223-
You can use an instance of :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\CallbackChoiceLoader`
224-
if you want to take advantage of lazy loading::
225-
226-
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
227-
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
228-
// ...
229-
230-
$builder->add('constants', ChoiceType::class, [
231-
'choice_loader' => new CallbackChoiceLoader(function() {
232-
return StaticClass::getConstants();
233-
}),
234-
]);
219+
.. _reference-form-choice-label:
235220

236-
This will cause the call of ``StaticClass::getConstants()`` to not happen if the
237-
request is redirected and if there is no pre set or submitted data. Otherwise
238-
the choice options would need to be resolved thus triggering the callback.
221+
.. include:: /reference/forms/types/options/choice_label.rst.inc
239222

240223
.. include:: /reference/forms/types/options/choice_name.rst.inc
241224

reference/forms/types/options/choice_attr.rst.inc

+18
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,21 @@ If an array, the keys of the ``choices`` array must be used as keys::
2424
return ['class' => 'attending_'.strtolower($key)];
2525
},
2626
]);
27+
28+
.. tip::
29+
30+
When defining a custom type, you should use the
31+
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::
32+
33+
use App\Entity\Category;
34+
use Symfony\Component\Form\ChoiceList\ChoiceList;
35+
use Symfony\Component\Form\ChoiceList\ChoiceList;
36+
37+
// ...
38+
$builder->add('choices', ChoiceType::class, [
39+
'choice_label' => ChoiceList::attr($this, function (?Category $category) {
40+
return $category ? ['data-uuid' => $category->getUuid()] : [];
41+
}),
42+
]);
43+
44+
See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.

reference/forms/types/options/choice_label.rst.inc

+14
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,17 @@ If your choice values are objects, then ``choice_label`` can also be a
5353

5454
If set to ``false``, all the tag labels will be discarded for radio or checkbox
5555
inputs. You can also return ``false`` from the callable to discard certain labels.
56+
57+
.. tip::
58+
59+
When defining a custom type, you should use the
60+
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::
61+
62+
use Symfony\Component\Form\ChoiceList\ChoiceList;
63+
64+
// ...
65+
$builder->add('choices', ChoiceType::class, [
66+
'choice_label' => ChoiceList::label($this, 'displayName'),
67+
]);
68+
69+
See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
choice_loader
2+
~~~~~~~~~~~~~
3+
4+
**type**: :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\ChoiceLoaderInterface`
5+
6+
The ``choice_loader`` can be used to only partially load the choices in cases where
7+
a fully-loaded list is not necessary. This is only needed in advanced cases and
8+
would replace the ``choices`` option.
9+
10+
You can use an instance of :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\CallbackChoiceLoader`
11+
if you want to take advantage of lazy loading::
12+
13+
use App\StaticClass;
14+
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
15+
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
16+
// ...
17+
18+
$builder->add('loaded_choices', ChoiceType::class, [
19+
'choice_loader' => new CallbackChoiceLoader(function() {
20+
return StaticClass::getConstants();
21+
}),
22+
]);
23+
24+
This will cause the call of ``StaticClass::getConstants()`` to not happen if the
25+
request is redirected and if there is no pre set or submitted data. Otherwise
26+
the choice options would need to be resolved thus triggering the callback.
27+
28+
When you're defining a custom choice type that may be reused in many fields
29+
(like entries of a collection) or reused in multiple forms at once, you
30+
should use the :class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList`
31+
static methods to wrap the loader and make the choice list cacheable for
32+
better performance::
33+
34+
use App\Form\ChoiceList\CustomChoiceLoader;
35+
use App\StaticClass;
36+
use Symfony\Component\Form\AbstractType;
37+
use Symfony\Component\Form\ChoiceList\ChoiceList;
38+
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
39+
use Symfony\Component\OptionsResolver\Options;
40+
use Symfony\Component\OptionsResolver\OptionsResolver;
41+
42+
class ConstantsType extends AbstractType
43+
{
44+
public static function getExtendedTypes(): iterable
45+
{
46+
return [ChoiceType::class];
47+
}
48+
49+
public function configureOptions(OptionsResolver $resolver)
50+
{
51+
$resolver->setDefaults([
52+
// the example below will create a CallbackChoiceLoader from the callable
53+
'choice_loader' => ChoiceList::lazy($this, function() {
54+
return StaticClass::getConstants();
55+
}),
56+
57+
// you can pass your own loader as well, depending on other options
58+
'some_key' => null,
59+
'choice_loader' => function (Options $options) {
60+
return ChoiceList::loader(
61+
// pass the instance of the type or type extension which is
62+
// currently configuring the choice list as first argument
63+
$this,
64+
// pass the other option to the loader
65+
new CustomChoiceLoader($options['some_key']),
66+
// ensure the type stores a loader per key
67+
// by using the special third argument "$vary"
68+
// an array containing anything that "changes" the loader
69+
[$options['some_key']]
70+
);
71+
},
72+
]);
73+
}
74+
}

reference/forms/types/options/choice_name.rst.inc

+15-1
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,26 @@
55

66
Controls the internal field name of the choice. You normally don't care about this,
77
but in some advanced cases, you might. For example, this "name" becomes the index
8-
of the choice views in the template and is used as part o the field name
8+
of the choice views in the template and is used as part of the field name
99
attribute.
1010

1111
This can be a callable or a property path. See `choice_label`_ for similar usage.
1212
By default, the choice key or an incrementing integer may be used (starting at ``0``).
1313

14+
.. tip::
15+
16+
When defining a custom type, you should use the
17+
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::
18+
19+
use Symfony\Component\Form\ChoiceList\ChoiceList;
20+
21+
// ...
22+
$builder->add('choices', ChoiceType::class, [
23+
'choice_name' => ChoiceList::fieldName($this, 'name'),
24+
]);
25+
26+
See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.
27+
1428
.. caution::
1529

1630
The configured value must be a valid form name. Make sure to only return

reference/forms/types/options/choice_value.rst.inc

+14
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,17 @@ for each choice or ``null`` in a placeholder is used, which you need to handle::
1818
'choice_value' => function (?MyOptionEntity $entity) {
1919
return $entity ? $entity->getId() : '';
2020
},
21+
22+
.. tip::
23+
24+
When defining a custom type, you should use the
25+
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::
26+
27+
use Symfony\Component\Form\ChoiceList\ChoiceList;
28+
29+
// ...
30+
$builder->add('choices', ChoiceType::class, [
31+
'choice_value' => ChoiceList::value($this, 'uuid'),
32+
]);
33+
34+
See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.

reference/forms/types/options/group_by.rst.inc

+14
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,17 @@ a "Later" ``<optgroup>``:
4040
If you return ``null``, the option won't be grouped. You can also pass a string
4141
"property path" that will be called to get the group. See the `choice_label`_ for
4242
details about using a property path.
43+
44+
.. tip::
45+
46+
When defining a custom type, you should use the
47+
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::
48+
49+
use Symfony\Component\Form\ChoiceList\ChoiceList;
50+
51+
// ...
52+
$builder->add('choices', ChoiceType::class, [
53+
'group_by' => ChoiceList::groupBy($this, 'category'),
54+
]);
55+
56+
See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.

reference/forms/types/options/preferred_choices.rst.inc

+14
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,17 @@ when rendering the field:
6363
<?= $view['form']->widget($form['publishAt'], [
6464
'separator' => '=====',
6565
]) ?>
66+
67+
.. tip::
68+
69+
When defining a custom type, you should use the
70+
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::
71+
72+
use Symfony\Component\Form\ChoiceList\ChoiceList;
73+
74+
// ...
75+
$builder->add('choices', ChoiceType::class, [
76+
'preferred_choices' => ChoiceList::preferred($this, 'taggedAsFavorite'),
77+
]);
78+
79+
See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.

0 commit comments

Comments
 (0)