5
5
The OptionsResolver Component
6
6
=============================
7
7
8
- The OptionsResolver component is `array_replace() ` on steroids.
8
+ The OptionsResolver component is :phpfunction: `array_replace ` on steroids.
9
+ It allows you to create an options system with required options, defaults,
10
+ validation (type, value), normalization and more.
9
11
10
12
Installation
11
13
------------
@@ -20,8 +22,8 @@ Notes on Previous Versions
20
22
21
23
.. versionadded :: 2.6
22
24
This documentation was written for Symfony 2.6 and later. If you use an older
23
- version, please read the corresponding documentation using the version
24
- drop-down on the upper right .
25
+ version, please ` read the Symfony 2.5 documentation `_. For a list of changes,
26
+ see the ` CHANGELOG `_ .
25
27
26
28
Usage
27
29
-----
@@ -48,29 +50,35 @@ check which options are set::
48
50
public function sendMail($from, $to)
49
51
{
50
52
$mail = ...;
53
+
51
54
$mail->setHost(isset($this->options['host'])
52
55
? $this->options['host']
53
56
: 'smtp.example.org');
57
+
54
58
$mail->setUsername(isset($this->options['username'])
55
59
? $this->options['username']
56
60
: 'user');
61
+
57
62
$mail->setPassword(isset($this->options['password'])
58
63
? $this->options['password']
59
64
: 'pa$$word');
65
+
60
66
$mail->setPort(isset($this->options['port'])
61
67
? $this->options['port']
62
68
: 25);
69
+
63
70
// ...
64
71
}
65
72
}
66
73
67
74
This boilerplate is hard to read and repetitive. Also, the default values of the
68
- options are buried in the business logic of your code. We can use
75
+ options are buried in the business logic of your code. Use the
69
76
:phpfunction: `array_replace ` to fix that::
70
77
71
78
class Mailer
72
79
{
73
80
// ...
81
+
74
82
public function __construct(array $options = array())
75
83
{
76
84
$this->options = array_replace(array(
@@ -83,27 +91,27 @@ options are buried in the business logic of your code. We can use
83
91
}
84
92
85
93
Now all four options are guaranteed to be set. But what happens if the user of
86
- the ``Mailer `` class does a mistake?
94
+ the ``Mailer `` class makes a mistake?
87
95
88
96
.. code-block :: php
89
97
90
98
$mailer = new Mailer(array(
91
99
'usernme' => 'johndoe',
92
100
));
93
101
94
- No error will be shown. In the best case, the bug will be appear during testing.
95
- The developer will possibly spend a lot of time looking for the problem. In the
96
- worst case, however, the bug won't even appear and will be deployed to the live
97
- system.
102
+ No error will be shown. In the best case, the bug will appear during testing,
103
+ but the developer will spend time looking for the problem. In the worst case,
104
+ the bug might not appear until it's deployed to the live system.
98
105
99
- Let's use the :class: `Symfony\\ Component\\ OptionsResolver\\ OptionsResolver `
100
- class to fix this problem::
106
+ Fortunately, the :class: `Symfony\\ Component\\ OptionsResolver\\ OptionsResolver `
107
+ class helps you to fix this problem::
101
108
102
109
use Symfony\Component\OptionsResolver\Options;
103
110
104
111
class Mailer
105
112
{
106
113
// ...
114
+
107
115
public function __construct(array $options = array())
108
116
{
109
117
$resolver = new OptionsResolver();
@@ -136,6 +144,7 @@ code::
136
144
class Mailer
137
145
{
138
146
// ...
147
+
139
148
public function sendMail($from, $to)
140
149
{
141
150
$mail = ...;
@@ -153,6 +162,7 @@ It's a good practice to split the option configuration into a separate method::
153
162
class Mailer
154
163
{
155
164
// ...
165
+
156
166
public function __construct(array $options = array())
157
167
{
158
168
$resolver = new OptionsResolver();
@@ -164,10 +174,10 @@ It's a good practice to split the option configuration into a separate method::
164
174
protected function configureOptions(OptionsResolver $resolver)
165
175
{
166
176
$resolver->setDefaults(array(
167
- 'host' => 'smtp.example.org',
168
- 'username' => 'user',
169
- 'password' => 'pa$$word',
170
- 'port' => 25,
177
+ 'host' => 'smtp.example.org',
178
+ 'username' => 'user',
179
+ 'password' => 'pa$$word',
180
+ 'port' => 25,
171
181
'encryption' => null,
172
182
));
173
183
}
@@ -196,12 +206,13 @@ Required Options
196
206
197
207
If an option must be set by the caller, pass that option to
198
208
:method: `Symfony\\ Component\\ OptionsResolver\\ OptionsResolver::setRequired `.
199
- For example, let's make the ``host `` option required::
209
+ For example, to make the ``host `` option required, you can do ::
200
210
201
211
// ...
202
212
class Mailer
203
213
{
204
214
// ...
215
+
205
216
protected function configureOptions(OptionsResolver $resolver)
206
217
{
207
218
// ...
@@ -210,8 +221,8 @@ For example, let's make the ``host`` option required::
210
221
}
211
222
212
223
.. versionadded :: 2.6
213
- Before Symfony 2.6, `setRequired() ` accepted only arrays. Since then, single
214
- option names can be passed as well .
224
+ As of Symfony 2.6, `` setRequired() `` accepts both an array of options or a
225
+ single option. Prior to 2.6, you could only pass arrays .
215
226
216
227
If you omit a required option, a
217
228
:class: `Symfony\\ Component\\ OptionsResolver\\ Exception\\ MissingOptionsException `
@@ -229,6 +240,7 @@ one required option::
229
240
class Mailer
230
241
{
231
242
// ...
243
+
232
244
protected function configureOptions(OptionsResolver $resolver)
233
245
{
234
246
// ...
@@ -268,14 +280,15 @@ retrieve the names of all required options::
268
280
269
281
If you want to check whether a required option is still missing from the default
270
282
options, you can use :method: `Symfony\\ Component\\ OptionsResolver\\ OptionsResolver::isMissing `.
271
- The difference to :method: `Symfony\\ Component\\ OptionsResolver\\ OptionsResolver::isRequired `
272
- is that this method will return false for required options that have already
283
+ The difference between this and :method: `Symfony\\ Component\\ OptionsResolver\\ OptionsResolver::isRequired `
284
+ is that this method will return false if a required option has already
273
285
been set::
274
286
275
287
// ...
276
288
class Mailer
277
289
{
278
290
// ...
291
+
279
292
protected function configureOptions(OptionsResolver $resolver)
280
293
{
281
294
// ...
@@ -320,6 +333,7 @@ correctly. To validate the types of the options, call
320
333
class Mailer
321
334
{
322
335
// ...
336
+
323
337
protected function configureOptions(OptionsResolver $resolver)
324
338
{
325
339
// ...
@@ -329,8 +343,8 @@ correctly. To validate the types of the options, call
329
343
}
330
344
331
345
For each option, you can define either just one type or an array of acceptable
332
- types. You can pass any type for which an ``is_<type>() `` method is defined.
333
- Additionally, you may pass fully qualified class or interface names.
346
+ types. You can pass any type for which an ``is_<type>() `` function is defined
347
+ in PHP. Additionally, you may pass fully qualified class or interface names.
334
348
335
349
If you pass an invalid option now, an
336
350
:class: `Symfony\\ Component\\ OptionsResolver\\ Exception\\ InvalidOptionsException `
@@ -348,9 +362,7 @@ to add additional allowed types without erasing the ones already set.
348
362
349
363
.. versionadded :: 2.6
350
364
Before Symfony 2.6, `setAllowedTypes() ` and `addAllowedTypes() ` expected
351
- the values to be given as an array mapping option names to allowed types:
352
-
353
- .. code-block :: php
365
+ the values to be given as an array mapping option names to allowed types::
354
366
355
367
$resolver->setAllowedTypes(array('port' => array('null', 'int')));
356
368
@@ -360,13 +372,14 @@ Value Validation
360
372
Some options can only take one of a fixed list of predefined values. For
361
373
example, suppose the ``Mailer `` class has a ``transport `` option which can be
362
374
one of ``sendmail ``, ``mail `` and ``smtp ``. Use the method
363
- :method: `Symfony\\ Component\\ OptionsResolver\\ OptionsResolver::setAllowedValues ` to verify
364
- that the passed option contains one of these values::
375
+ :method: `Symfony\\ Component\\ OptionsResolver\\ OptionsResolver::setAllowedValues `
376
+ to verify that the passed option contains one of these values::
365
377
366
378
// ...
367
379
class Mailer
368
380
{
369
381
// ...
382
+
370
383
protected function configureOptions(OptionsResolver $resolver)
371
384
{
372
385
// ...
@@ -420,9 +433,11 @@ option. You can configure a normalizer by calling
420
433
class Mailer
421
434
{
422
435
// ...
436
+
423
437
protected function configureOptions(OptionsResolver $resolver)
424
438
{
425
439
// ...
440
+
426
441
$resolver->setNormalizer('host', function ($options, $value) {
427
442
if ('http://' !== substr($value, 0, 7)) {
428
443
$value = 'http://'.$value;
@@ -467,12 +482,12 @@ Default Values that Depend on another Option
467
482
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
468
483
469
484
Suppose you want to set the default value of the ``port `` option based on the
470
- encryption chosen by the user of the ``Mailer `` class. More precisely, we want
485
+ encryption chosen by the user of the ``Mailer `` class. More precisely, you want
471
486
to set the port to ``465 `` if SSL is used and to ``25 `` otherwise.
472
487
473
- You can implement this feature by passing a closure as default value of the
474
- ``port `` option. The closure receives the options as argument. Based on these
475
- options, you can return the desired default value::
488
+ You can implement this feature by passing a closure as the default value of
489
+ the ``port `` option. The closure receives the options as argument. Based on
490
+ these options, you can return the desired default value::
476
491
477
492
use Symfony\Component\OptionsResolver\Options;
478
493
@@ -498,7 +513,7 @@ options, you can return the desired default value::
498
513
.. caution ::
499
514
500
515
The argument of the callable must be type hinted as ``Options ``. Otherwise,
501
- the callable is considered as the default value of the option.
516
+ the callable itself is considered as the default value of the option.
502
517
503
518
.. note ::
504
519
@@ -546,8 +561,10 @@ Options without Default Values
546
561
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
547
562
548
563
In some cases, it is useful to define an option without setting a default value.
549
- Mostly, you will need this when you want to know whether an option was passed
550
- or not. If you set a default value for that option, this is not possible::
564
+ This is useful if you need to know whether or not the user *actually * set
565
+ an option or not. For example, if you set the default value for an option,
566
+ it's not possible to know whether the user passed this value or if it simply
567
+ comes from the default::
551
568
552
569
// ...
553
570
class Mailer
@@ -584,6 +601,7 @@ be included in the resolved options if it was actually passed to
584
601
class Mailer
585
602
{
586
603
// ...
604
+
587
605
protected function configureOptions(OptionsResolver $resolver)
588
606
{
589
607
// ...
@@ -637,6 +655,8 @@ let you find out which options are defined::
637
655
// ...
638
656
class GoogleMailer extends Mailer
639
657
{
658
+ // ...
659
+
640
660
protected function configureOptions(OptionsResolver $resolver)
641
661
{
642
662
parent::configureOptions($resolver);
@@ -671,10 +691,10 @@ can change your code to do the configuration only once per class::
671
691
672
692
public function __construct(array $options = array())
673
693
{
674
- // Are we a Mailer, a GoogleMailer, ... ?
694
+ // What type of Mailer is this, a Mailer, a GoogleMailer, ... ?
675
695
$class = get_class($this);
676
696
677
- // Did we call configureOptions() before for this class?
697
+ // Was configureOptions() executed before for this class?
678
698
if (!isset(self::$resolversByClass[$class])) {
679
699
self::$resolversByClass[$class] = new OptionsResolver();
680
700
$this->configureOptions(self::$resolversByClass[$class]);
@@ -693,14 +713,14 @@ Now the :class:`Symfony\\Component\\OptionsResolver\\OptionsResolver` instance
693
713
will be created once per class and reused from that on. Be aware that this may
694
714
lead to memory leaks in long-running applications, if the default options contain
695
715
references to objects or object graphs. If that's the case for you, implement a
696
- method ``clearDefaultOptions () `` and call it periodically::
716
+ method ``clearOptionsConfig () `` and call it periodically::
697
717
698
718
// ...
699
719
class Mailer
700
720
{
701
721
private static $resolversByClass = array();
702
722
703
- public static function clearDefaultOptions ()
723
+ public static function clearOptionsConfig ()
704
724
{
705
725
self::$resolversByClass = array();
706
726
}
@@ -713,3 +733,5 @@ options in your code.
713
733
714
734
.. _Packagist : https://packagist.org/packages/symfony/options-resolver
715
735
.. _Form component : http://symfony.com/doc/current/components/form/introduction.html
736
+ .. _CHANGELOG : https://github.com/symfony/symfony/blob/master/src/Symfony/Component/OptionsResolver/CHANGELOG.md#260
737
+ .. _`read the Symfony 2.5 documentation` : http://symfony.com/doc/2.5/components/options_resolver.html
0 commit comments