Skip to content

Commit 10ef814

Browse files
committed
Merge branch '4.2'
* 4.2: [OptionsResolver] Documenting nested options feature Add missing imports in Data Mappers article fix code style Complete code example for \"Adding validation\" part
2 parents 9b43d07 + 7c1b3a0 commit 10ef814

File tree

4 files changed

+114
-12
lines changed

4 files changed

+114
-12
lines changed

components/options_resolver.rst

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,101 @@ let you find out which options are defined::
634634
}
635635
}
636636

637+
Nested Options
638+
~~~~~~~~~~~~~~
639+
640+
.. versionadded:: 4.2
641+
The support of nested options was introduced in Symfony 4.2.
642+
643+
Suppose you have an option named ``spool`` which has two sub-options ``type``
644+
and ``path``. Instead of defining it as a simple array of values, you can pass a
645+
closure as the default value of the ``spool`` option with a
646+
:class:`Symfony\\Component\\OptionsResolver\\OptionsResolver` argument. Based on
647+
this instance, you can define the options under ``spool`` and its desired
648+
default value::
649+
650+
class Mailer
651+
{
652+
// ...
653+
654+
public function configureOptions(OptionsResolver $resolver)
655+
{
656+
$resolver->setDefault('spool', function (OptionsResolver $spoolResolver) {
657+
$spoolResolver->setDefaults(array(
658+
'type' => 'file',
659+
'path' => '/path/to/spool',
660+
));
661+
$spoolResolver->setAllowedValues('type', array('file', 'memory'));
662+
$spoolResolver->setAllowedTypes('path', 'string');
663+
});
664+
}
665+
666+
public function sendMail($from, $to)
667+
{
668+
if ('memory' === $this->options['spool']['type']) {
669+
// ...
670+
}
671+
}
672+
}
673+
674+
$mailer = new Mailer(array(
675+
'spool' => array(
676+
'type' => 'memory',
677+
),
678+
));
679+
680+
Nested options also support required options, validation (type, value) and
681+
normalization of their values. If the default value of a nested option depends
682+
on another option defined in the parent level, add a second ``Options`` argument
683+
to the closure to access to them::
684+
685+
class Mailer
686+
{
687+
// ...
688+
689+
public function configureOptions(OptionsResolver $resolver)
690+
{
691+
$resolver->setDefault('sandbox', false);
692+
$resolver->setDefault('spool', function (OptionsResolver $spoolResolver, Options $parent) {
693+
$spoolResolver->setDefaults(array(
694+
'type' => $parent['sandbox'] ? 'memory' : 'file',
695+
// ...
696+
));
697+
});
698+
}
699+
}
700+
701+
.. caution::
702+
703+
The arguments of the closure must be type hinted as ``OptionsResolver`` and
704+
``Options`` respectively. Otherwise, the closure itself is considered as the
705+
default value of the option.
706+
707+
In same way, parent options can access to the nested options as normal arrays::
708+
709+
class Mailer
710+
{
711+
// ...
712+
713+
public function configureOptions(OptionsResolver $resolver)
714+
{
715+
$resolver->setDefault('spool', function (OptionsResolver $spoolResolver) {
716+
$spoolResolver->setDefaults(array(
717+
'type' => 'file',
718+
// ...
719+
));
720+
});
721+
$resolver->setDefault('profiling', function (Options $options) {
722+
return 'file' === $options['spool']['type'];
723+
});
724+
}
725+
}
726+
727+
.. note::
728+
729+
The fact that an option is defined as nested means that you must pass
730+
an array of values to resolve it at runtime.
731+
637732
Deprecating the Option
638733
~~~~~~~~~~~~~~~~~~~~~~
639734

form/data_mappers.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,10 @@ method to configure the data mapper::
149149
namespace App\Form\Type;
150150

151151
use App\Form\DataMapper\ColorMapper;
152+
use Symfony\Component\Form\AbstractType;
152153
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
154+
use Symfony\Component\Form\FormBuilderInterface;
155+
use Symfony\Component\OptionsResolver\OptionsResolver;
153156

154157
final class ColorType extends AbstractType
155158
{

form/without_class.rst

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,22 @@ but here's a short example::
8282
use Symfony\Component\Validator\Constraints\Length;
8383
use Symfony\Component\Validator\Constraints\NotBlank;
8484
use Symfony\Component\Form\Extension\Core\Type\TextType;
85+
use Symfony\Component\Form\FormBuilderInterface;
8586

86-
$builder
87-
->add('firstName', TextType::class, array(
88-
'constraints' => new Length(array('min' => 3)),
89-
))
90-
->add('lastName', TextType::class, array(
91-
'constraints' => array(
92-
new NotBlank(),
93-
new Length(array('min' => 3)),
94-
),
95-
))
96-
;
87+
public function buildForm(FormBuilderInterface $builder, array $options)
88+
{
89+
$builder
90+
->add('firstName', TextType::class, array(
91+
'constraints' => new Length(array('min' => 3)),
92+
))
93+
->add('lastName', TextType::class, array(
94+
'constraints' => array(
95+
new NotBlank(),
96+
new Length(array('min' => 3)),
97+
),
98+
))
99+
;
100+
}
97101

98102
.. tip::
99103

validation/custom_constraint.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ The validator class is also simple, and only has one required method ``validate(
6666
public function validate($value, Constraint $constraint)
6767
{
6868
if (!$constraint instanceof ContainsAlphanumeric) {
69-
throw new UnexpectedTypeException($constraint, ContainsAlphanumeric::class);
69+
throw new UnexpectedTypeException($constraint, ContainsAlphanumeric::class);
7070
}
7171
7272
// custom constraints should ignore null and empty values to allow

0 commit comments

Comments
 (0)