@@ -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+
637732Deprecating the Option
638733~~~~~~~~~~~~~~~~~~~~~~
639734
0 commit comments