8000 [Form] added the new `ChoiceList` class to configure `ChoiceType` options by HeahDude · Pull Request #13182 · symfony/symfony-docs · GitHub
[go: up one dir, main page]

Skip to content

[Form] added the new ChoiceList class to configure ChoiceType options #13182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 7 additions & 24 deletions reference/forms/types/choice.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ To get fancier, use the `group_by`_ option instead.
Field Options
-------------

.. versionadded:: 5.1

The :class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class has
been introduced in Symfony 5.1, to help configuring choices options.

choices
~~~~~~~

Expand Down Expand Up @@ -211,31 +216,9 @@ correct types will be assigned to the model.

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

choice_loader
~~~~~~~~~~~~~

**type**: :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\ChoiceLoaderInterface`

The ``choice_loader`` can be used to only partially load the choices in cases where
a fully-loaded list is not necessary. This is only needed in advanced cases and
would replace the ``choices`` option.

You can use an instance of :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\CallbackChoiceLoader`
if you want to take advantage of lazy loading::

use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('constants', ChoiceType::class, [
'choice_loader' => new CallbackChoiceLoader(function() {
return StaticClass::getConstants();
}),
]);
.. _reference-form-choice-loader:

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

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

Expand Down
17 changes: 17 additions & 0 deletions reference/forms/types/options/choice_attr.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,20 @@ If an array, the keys of the ``choices`` array must be used as keys::
return ['class' => 'attending_'.strtolower($key)];
},
]);

.. tip::

When defining a custom type, you should use the
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::

use App\Entity\Category;
use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
'choice_label' => ChoiceList::attr($this, function (?Category $category) {
return $category ? ['data-uuid' => $category->getUuid()] : [];
}),
]);

See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.
14 changes: 14 additions & 0 deletions reference/forms/types/options/choice_label.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,17 @@ If your choice values are objects, then ``choice_label`` can also be a

If set to ``false``, all the tag labels will be discarded for radio or checkbox
inputs. You can also return ``false`` from the callable to discard certain labels.

.. tip::

When defining a custom type, you should use the
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::

use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
'choice_label' => ChoiceList::label($this, 'displayName'),
]);

See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.
75 changes: 75 additions & 0 deletions reference/forms/types/options/choice_loader.rst.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
choice_loader
~~~~~~~~~~~~~

**type**: :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\ChoiceLoaderInterface`

The ``choice_loader`` can be used instead of ``choices`` option. It allows to
create a list lazily or partially when fetching only the choices for a set of
submitted values (i.e. querying a search engine like ``ElasticSearch`` can be
a heavy process).

You can use an instance of :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\CallbackChoiceLoader`
if you want to take advantage of lazy loading::

use App\StaticClass;
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// ...

$builder->add('loaded_choices', ChoiceType::class, [
'choice_loader' => new CallbackChoiceLoader(function() {
return StaticClass::getConstants();
}),
]);

This will cause the call of ``StaticClass::getConstants()`` to not happen if the
request is redirected and if there is no pre set or submitted data. Otherwise
the choice options would need to be resolved thus triggering the callback.

When you're defining a custom choice type that may be reused in many fields
(like entries of a collection) or reused in multiple forms at once, you
should use the :class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList`
static methods to wrap the loader and make the choice list cacheable for
better performance::

use App\Form\ChoiceList\CustomChoiceLoader;
use App\StaticClass;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\ChoiceList\ChoiceList;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ConstantsType extends AbstractType
{
public static function getExtendedTypes(): iterable
{
return [ChoiceType::class];
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
// the example below will create a CallbackChoiceLoader from the callable
'choice_loader' => ChoiceList::lazy($this, function() {
return StaticClass::getConstants();
}),

// you can pass your own loader as well, depending on other options
'some_key' => null,
'choice_loader' => function (Options $options) {
return ChoiceList::loader(
// pass the instance of the type or type extension which is
// currently configuring the choice list as first argument
$this,
// pass the other option to the loader
new CustomChoiceLoader($options['some_key']),
// ensure the type stores a loader per key
// by using the special third argument "$vary"
// an array containing anything that "changes" the loader
[$options['some_key']]
);
},
]);
}
}
16 changes: 15 additions & 1 deletion reference/forms/types/options/choice_name.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,26 @@

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

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

.. tip::

When defining a custom type, you should use the
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::

use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
'choice_name' => ChoiceList::fieldName($this, 'name'),
]);

See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.

.. caution::

The configured value must be a valid form name. Make sure to only return
Expand Down
14 changes: 14 additions & 0 deletions reference/forms/types/options/choice_value.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,17 @@ for each choice or ``null`` in a placeholder is used, which you need to handle::
'choice_value' => function (?MyOptionEntity $entity) {
return $entity ? $entity->getId() : '';
},

.. tip::

When defining a custom type, you should use the
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::

use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
'choice_value' => ChoiceList::value($this, 'uuid'),
]);

See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.
14 changes: 14 additions & 0 deletions reference/forms/types/options/group_by.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,17 @@ a "Later" ``<optgroup>``:
If you return ``null``, the option won't be grouped. You can also pass a string
"property path" that will be called to get the group. See the `choice_label`_ for
details about using a property path.

.. tip::

When defining a custom type, you should use the
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::

use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
'group_by' => ChoiceList::groupBy($this, 'category'),
]);

See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.
14 changes: 14 additions & 0 deletions reference/forms/types/options/preferred_choices.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,17 @@ 6075 when rendering the field:
<?= $view['form']->widget($form['publishAt'], [
'separator' => '=====',
]) ?>

.. tip::

When defining a custom type, you should use the
:class:`Symfony\\Component\\Form\\ChoiceList\\ChoiceList` class helper::

use Symfony\Component\Form\ChoiceList\ChoiceList;

// ...
$builder->add('choices', ChoiceType::class, [
'preferred_choices' => ChoiceList::preferred($this, 'taggedAsFavorite'),
]);

See the :ref:`"choice_loader" option documentation <reference-form-choice-loader>`.
0