From d190831c8918a17126588aa75960c8f6f2647b91 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sat, 25 Oct 2014 12:50:50 -0400 Subject: [PATCH 1/5] Tweaks after proofreading the 2.6 OptionsResolver stuff --- components/options_resolver.rst | 36 ++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index ea1372f4ea6..d11c4965752 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -5,7 +5,9 @@ The OptionsResolver Component ============================= - The OptionsResolver component is `array_replace()` on steroids. + The OptionsResolver component is `array_replace()` on steroids. It + allows you to create an options system with required options, defaults, + validation (type, value), normalization and more. Installation ------------ @@ -21,7 +23,7 @@ Notes on Previous Versions .. versionadded:: 2.6 This documentation was written for Symfony 2.6 and later. If you use an older version, please read the corresponding documentation using the version - drop-down on the upper right. + drop-down on the upper right. For a list of changes, see the `CHANGELOG`_ Usage ----- @@ -65,7 +67,7 @@ check which options are set:: } This boilerplate is hard to read and repetitive. Also, the default values of the -options are buried in the business logic of your code. We can use +options are buried in the business logic of your code. We can use the :phpfunction:`array_replace` to fix that:: class Mailer @@ -91,10 +93,9 @@ the ``Mailer`` class does a mistake? 'usernme' => 'johndoe', )); -No error will be shown. In the best case, the bug will be appear during testing. -The developer will possibly spend a lot of time looking for the problem. In the -worst case, however, the bug won't even appear and will be deployed to the live -system. +No error will be shown. In the best case, the bug will appear during testing, +but the developer will spend time looking for the problem. In the worst case, +the bug might not appear until it's deployed to the live system. Let's use the :class:`Symfony\\Component\\OptionsResolver\\OptionsResolver` class to fix this problem:: @@ -268,8 +269,8 @@ retrieve the names of all required options:: If you want to check whether a required option is still missing from the default options, you can use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isMissing`. -The difference to :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isRequired` -is that this method will return false for required options that have already +The difference between this and :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isRequired` +is that this method will return false if a required option has already been set:: // ... @@ -360,8 +361,8 @@ Value Validation Some options can only take one of a fixed list of predefined values. For example, suppose the ``Mailer`` class has a ``transport`` option which can be one of ``sendmail``, ``mail`` and ``smtp``. Use the method -:method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setAllowedValues` to verify -that the passed option contains one of these values:: +:method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setAllowedValues` +to verify that the passed option contains one of these values:: // ... class Mailer @@ -470,9 +471,9 @@ Suppose you want to set the default value of the ``port`` option based on the encryption chosen by the user of the ``Mailer`` class. More precisely, we want to set the port to ``465`` if SSL is used and to ``25`` otherwise. -You can implement this feature by passing a closure as default value of the -``port`` option. The closure receives the options as argument. Based on these -options, you can return the desired default value:: +You can implement this feature by passing a closure as the default value of +the ``port`` option. The closure receives the options as argument. Based on +these options, you can return the desired default value:: use Symfony\Component\OptionsResolver\Options; @@ -546,8 +547,10 @@ Options without Default Values ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In some cases, it is useful to define an option without setting a default value. -Mostly, you will need this when you want to know whether an option was passed -or not. If you set a default value for that option, this is not possible:: +This is useful if you need to know whether or not the user *actually* set +an option or not. For example, if you set the default value for an option, +it's not possible to know whether the user passed this value or if it simply +comes from the default:: // ... class Mailer @@ -713,3 +716,4 @@ options in your code. .. _Packagist: https://packagist.org/packages/symfony/options-resolver .. _Form component: http://symfony.com/doc/current/components/form/introduction.html +.. _CHANGELOG: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/OptionsResolver/CHANGELOG.md From 59fd436a5705702d71e3bfbf2f9b3aad0abca0bb Mon Sep 17 00:00:00 2001 From: WouterJ Date: Sat, 25 Oct 2014 19:54:56 +0200 Subject: [PATCH 2/5] Also did a quick proofread --- components/options_resolver.rst | 63 +++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index d11c4965752..dd6229e0a78 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -5,8 +5,8 @@ The OptionsResolver Component ============================= - The OptionsResolver component is `array_replace()` on steroids. It - allows you to create an options system with required options, defaults, + The OptionsResolver component is :phpfunction:`array_replace` on steroids. + It allows you to create an options system with required options, defaults, validation (type, value), normalization and more. Installation @@ -23,7 +23,7 @@ Notes on Previous Versions .. versionadded:: 2.6 This documentation was written for Symfony 2.6 and later. If you use an older version, please read the corresponding documentation using the version - drop-down on the upper right. For a list of changes, see the `CHANGELOG`_ + drop-down on the upper right. For a list of changes, see the `CHANGELOG`_. Usage ----- @@ -50,29 +50,35 @@ check which options are set:: public function sendMail($from, $to) { $mail = ...; + $mail->setHost(isset($this->options['host']) ? $this->options['host'] : 'smtp.example.org'); + $mail->setUsername(isset($this->options['username']) ? $this->options['username'] : 'user'); + $mail->setPassword(isset($this->options['password']) ? $this->options['password'] : 'pa$$word'); + $mail->setPort(isset($this->options['port']) ? $this->options['port'] : 25); + // ... } } This boilerplate is hard to read and repetitive. Also, the default values of the -options are buried in the business logic of your code. We can use the +options are buried in the business logic of your code. You could use the :phpfunction:`array_replace` to fix that:: class Mailer { // ... + public function __construct(array $options = array()) { $this->options = array_replace(array( @@ -85,7 +91,7 @@ options are buried in the business logic of your code. We can use the } Now all four options are guaranteed to be set. But what happens if the user of -the ``Mailer`` class does a mistake? +the ``Mailer`` class makes a mistake? .. code-block:: php @@ -97,14 +103,15 @@ No error will be shown. In the best case, the bug will appear during testing, but the developer will spend time looking for the problem. In the worst case, the bug might not appear until it's deployed to the live system. -Let's use the :class:`Symfony\\Component\\OptionsResolver\\OptionsResolver` -class to fix this problem:: +Fortunately, the :class:`Symfony\\Component\\OptionsResolver\\OptionsResolver` +class helps you to fix this problem:: use Symfony\Component\OptionsResolver\Options; class Mailer { // ... + public function __construct(array $options = array()) { $resolver = new OptionsResolver(); @@ -137,6 +144,7 @@ code:: class Mailer { // ... + public function sendMail($from, $to) { $mail = ...; @@ -154,6 +162,7 @@ It's a good practice to split the option configuration into a separate method:: class Mailer { // ... + public function __construct(array $options = array()) { $resolver = new OptionsResolver(); @@ -165,10 +174,10 @@ It's a good practice to split the option configuration into a separate method:: protected function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( - 'host' => 'smtp.example.org', - 'username' => 'user', - 'password' => 'pa$$word', - 'port' => 25, + 'host' => 'smtp.example.org', + 'username' => 'user', + 'password' => 'pa$$word', + 'port' => 25, 'encryption' => null, )); } @@ -197,12 +206,13 @@ Required Options If an option must be set by the caller, pass that option to :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setRequired`. -For example, let's make the ``host`` option required:: +For example, to make the ``host`` option required, you can do:: // ... class Mailer { // ... + protected function configureOptions(OptionsResolver $resolver) { // ... @@ -211,8 +221,8 @@ For example, let's make the ``host`` option required:: } .. versionadded:: 2.6 - Before Symfony 2.6, `setRequired()` accepted only arrays. Since then, single - option names can be passed as well. + As of Symfony 2.6, ``setRequired()`` accepts both an array of options or a + single option. Prior to 2.6, you could only pass arrays. If you omit a required option, a :class:`Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException` @@ -230,6 +240,7 @@ one required option:: class Mailer { // ... + protected function configureOptions(OptionsResolver $resolver) { // ... @@ -277,6 +288,7 @@ been set:: class Mailer { // ... + protected function configureOptions(OptionsResolver $resolver) { // ... @@ -321,6 +333,7 @@ correctly. To validate the types of the options, call class Mailer { // ... + protected function configureOptions(OptionsResolver $resolver) { // ... @@ -330,8 +343,8 @@ correctly. To validate the types of the options, call } For each option, you can define either just one type or an array of acceptable -types. You can pass any type for which an ``is_()`` method is defined. -Additionally, you may pass fully qualified class or interface names. +types. You can pass any type for which an ``is_()`` function is defined +in PHP. Additionally, you may pass fully qualified class or interface names. If you pass an invalid option now, an :class:`Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException` @@ -349,9 +362,7 @@ to add additional allowed types without erasing the ones already set. .. versionadded:: 2.6 Before Symfony 2.6, `setAllowedTypes()` and `addAllowedTypes()` expected - the values to be given as an array mapping option names to allowed types: - - .. code-block:: php + the values to be given as an array mapping option names to allowed types:: $resolver->setAllowedTypes(array('port' => array('null', 'int'))); @@ -368,6 +379,7 @@ to verify that the passed option contains one of these values:: class Mailer { // ... + protected function configureOptions(OptionsResolver $resolver) { // ... @@ -421,9 +433,11 @@ option. You can configure a normalizer by calling class Mailer { // ... + protected function configureOptions(OptionsResolver $resolver) { // ... + $resolver->setNormalizer('host', function ($options, $value) { if ('http://' !== substr($value, 0, 7)) { $value = 'http://'.$value; @@ -468,7 +482,7 @@ Default Values that Depend on another Option ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Suppose you want to set the default value of the ``port`` option based on the -encryption chosen by the user of the ``Mailer`` class. More precisely, we want +encryption chosen by the user of the ``Mailer`` class. More precisely, you want to set the port to ``465`` if SSL is used and to ``25`` otherwise. You can implement this feature by passing a closure as the default value of @@ -499,7 +513,7 @@ these options, you can return the desired default value:: .. caution:: The argument of the callable must be type hinted as ``Options``. Otherwise, - the callable is considered as the default value of the option. + the callable itself is considered as the default value of the option. .. note:: @@ -587,6 +601,7 @@ be included in the resolved options if it was actually passed to class Mailer { // ... + protected function configureOptions(OptionsResolver $resolver) { // ... @@ -640,6 +655,8 @@ let you find out which options are defined:: // ... class GoogleMailer extends Mailer { + // ... + protected function configureOptions(OptionsResolver $resolver) { parent::configureOptions($resolver); @@ -674,10 +691,10 @@ can change your code to do the configuration only once per class:: public function __construct(array $options = array()) { - // Are we a Mailer, a GoogleMailer, ... ? + // What type of Mailer is this, a Mailer, a GoogleMailer, ... ? $class = get_class($this); - // Did we call configureOptions() before for this class? + // Was configureOptions() executed before for this class? if (!isset(self::$resolversByClass[$class])) { self::$resolversByClass[$class] = new OptionsResolver(); $this->configureOptions(self::$resolversByClass[$class]); From f179ec7f6df63e8f76962d8165f14d4d66b42ef6 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 28 Oct 2014 07:17:26 -0700 Subject: [PATCH 3/5] A few more tweaks from comments --- components/options_resolver.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index dd6229e0a78..3cb4c42cd1b 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -22,8 +22,8 @@ Notes on Previous Versions .. versionadded:: 2.6 This documentation was written for Symfony 2.6 and later. If you use an older - version, please read the corresponding documentation using the version - drop-down on the upper right. For a list of changes, see the `CHANGELOG`_. + version, please `read the Symfony 2.5 documentation`_. For a list of changes, + see the `CHANGELOG`_. Usage ----- @@ -72,7 +72,7 @@ check which options are set:: } This boilerplate is hard to read and repetitive. Also, the default values of the -options are buried in the business logic of your code. You could use the +options are buried in the business logic of your code. Use the :phpfunction:`array_replace` to fix that:: class Mailer @@ -734,3 +734,4 @@ options in your code. .. _Packagist: https://packagist.org/packages/symfony/options-resolver .. _Form component: http://symfony.com/doc/current/components/form/introduction.html .. _CHANGELOG: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/OptionsResolver/CHANGELOG.md +.. _`read the Symfony 2.5 documentation`: http://symfony.com/doc/2.5/components/options_resolver.html From a1badc5716553ec3e6cb110aa999c67f74d37f20 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 28 Oct 2014 07:17:57 -0700 Subject: [PATCH 4/5] Renaming a method at the suggestion of my friend Bernhard --- components/options_resolver.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 3cb4c42cd1b..4af7e757e68 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -713,14 +713,14 @@ Now the :class:`Symfony\\Component\\OptionsResolver\\OptionsResolver` instance will be created once per class and reused from that on. Be aware that this may lead to memory leaks in long-running applications, if the default options contain references to objects or object graphs. If that's the case for you, implement a -method ``clearDefaultOptions()`` and call it periodically:: +method ``clearOptionsConfig()`` and call it periodically:: // ... class Mailer { private static $resolversByClass = array(); - public static function clearDefaultOptions() + public static function clearOptionsConfig() { self::$resolversByClass = array(); } From b49731bc179d3fa16f48c0525b232444e9c30dd8 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 28 Oct 2014 07:24:54 -0700 Subject: [PATCH 5/5] Linking to the 2.6 headline thanks to a suggestion from @xabbuh --- components/options_resolver.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 4af7e757e68..7e85bf3c3cf 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -733,5 +733,5 @@ options in your code. .. _Packagist: https://packagist.org/packages/symfony/options-resolver .. _Form component: http://symfony.com/doc/current/components/form/introduction.html -.. _CHANGELOG: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/OptionsResolver/CHANGELOG.md +.. _CHANGELOG: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/OptionsResolver/CHANGELOG.md#260 .. _`read the Symfony 2.5 documentation`: http://symfony.com/doc/2.5/components/options_resolver.html