From 6a03408ce0eb447fd03885b594826eb1e499c398 Mon Sep 17 00:00:00 2001 From: unexge Date: Mon, 28 Dec 2015 23:13:07 +0200 Subject: [PATCH 1/6] [OptionsResolver] added frozen options --- .../Exception/OptionFrozenException.php | 19 ++++++ .../OptionsResolver/OptionsResolver.php | 66 ++++++++++++++++++- .../Tests/OptionsResolverTest.php | 33 ++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/OptionsResolver/Exception/OptionFrozenException.php diff --git a/src/Symfony/Component/OptionsResolver/Exception/OptionFrozenException.php b/src/Symfony/Component/OptionsResolver/Exception/OptionFrozenException.php new file mode 100644 index 0000000000000..cbd6e8f1208b7 --- /dev/null +++ b/src/Symfony/Component/OptionsResolver/Exception/OptionFrozenException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Exception thrown when a frozen option is setted. + */ +class OptionFrozenException extends InvalidArgumentException +{ +} diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index bcaea9e4cbc0f..8e73e502e4c16 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -16,6 +16,7 @@ use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; use Symfony\Component\OptionsResolver\Exception\NoSuchOptionException; use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException; +use Symfony\Component\OptionsResolver\Exception\OptionFrozenException; use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException; /** @@ -54,6 +55,13 @@ class OptionsResolver implements Options */ private $resolved = array(); + /** + * The frozen options. + * + * @var array + */ + private $frozen = array(); + /** * A list of normalizer closures. * @@ -366,6 +374,53 @@ public function getDefinedOptions() return array_keys($this->defined); } + /** + * Freeze the option with the given name. + * + * @param string|string[] $optionNames One or more option names + * + * @return OptionsResolver This instance + * + * @throws AccessException If called from a lazy option or normalizer + */ + public function setFrozen($optionNames) + { + if ($this->locked) { + throw new AccessException('Options cannot be freeze from a lazy option or normalizer.'); + } + + foreach ((array) $optionNames as $option) { + $this->frozen[$option] = true; + } + + return $this; + } + + /** + * Returns whether an option is frozen. + * + * @param string $option The option name + * + * @return bool Whether the option is frozen + */ + public function isFrozen($option) + { + return isset($this->frozen[$option]); + } + + /** + * Returns the names of all frozen options. + * + * @return string[] The names of the frozen options + * + * @see isFrozen() + */ + public function getFrozenOptions() + { + return array_keys($this->frozen); + } + + /** * Sets the normalizer for an option. * @@ -610,7 +665,7 @@ public function remove($optionNames) } foreach ((array) $optionNames as $option) { - unset($this->defined[$option], $this->defaults[$option], $this->required[$option], $this->resolved[$option]); + unset($this->defined[$option], $this->defaults[$option], $this->required[$option], $this->resolved[$option], $this->frozen[$option]); unset($this->lazy[$option], $this->normalizers[$option], $this->allowedTypes[$option], $this->allowedValues[$option]); } @@ -633,6 +688,7 @@ public function clear() $this->defined = array(); $this->defaults = array(); $this->required = array(); + $this->frozen = array(); $this->resolved = array(); $this->lazy = array(); $this->normalizers = array(); @@ -658,6 +714,7 @@ public function clear() * @return array The merged and validated options * * @throws UndefinedOptionsException If an option name is undefined + * @throws OptionFrozenException If a frozen option is setted * @throws InvalidOptionsException If an option doesn't fulfill the * specified validation rules * @throws MissingOptionsException If a required option is missing @@ -691,6 +748,13 @@ public function resolve(array $options = array()) // Override options set by the user foreach ($options as $option => $value) { + if (isset($this->frozen[$option])) { + throw new OptionFrozenException(sprintf( + 'The option "%s" is frozen. You cannot change it\'s value.', + $option + )); + } + $clone->defaults[$option] = $value; unset($clone->resolved[$option], $clone->lazy[$option]); } diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index 4f21bbaa3b824..510cf12d8fc7c 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -371,6 +371,39 @@ public function testGetMissingOptions() $this->assertSame(array('bar'), $this->resolver->getMissingOptions()); } + //////////////////////////////////////////////////////////////////////////// + // setFrozen()/isFrozen()/getFrozenOptions() + //////////////////////////////////////////////////////////////////////////// + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionFrozenException + * @expectedExceptionMessage The option "foo" is frozen. You cannot change it's value. + */ + public function testFailIfFrozenOptionSetted() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setFrozen('foo'); + + $this->resolver->resolve(array('foo' => 'baz')); + } + + public function testIsFrozen() + { + $this->assertFalse($this->resolver->isFrozen('foo')); + $this->resolver->setFrozen('foo'); + $this->assertTrue($this->resolver->isFrozen('foo')); + } + + public function testGetFrozenOptions() + { + $this->assertEquals(array(), $this->resolver->getFrozenOptions()); + + $this->resolver->setFrozen(array('foo', 'bar', 'baz')); + + $this->assertEquals(array('foo', 'bar', 'baz'), $this->resolver->getFrozenOptions()); + } + + //////////////////////////////////////////////////////////////////////////// // setDefined()/isDefined()/getDefinedOptions() //////////////////////////////////////////////////////////////////////////// From 8a52e1f37d0d1a6ac57fd8b58b92d5149309d0bc Mon Sep 17 00:00:00 2001 From: unexge Date: Tue, 29 Dec 2015 19:44:45 +0200 Subject: [PATCH 2/6] fix cs and typo --- .../OptionsResolver/Exception/OptionFrozenException.php | 2 +- src/Symfony/Component/OptionsResolver/OptionsResolver.php | 1 - .../Component/OptionsResolver/Tests/OptionsResolverTest.php | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Symfony/Component/OptionsResolver/Exception/OptionFrozenException.php b/src/Symfony/Component/OptionsResolver/Exception/OptionFrozenException.php index cbd6e8f1208b7..f25b2cc82224c 100644 --- a/src/Symfony/Component/OptionsResolver/Exception/OptionFrozenException.php +++ b/src/Symfony/Component/OptionsResolver/Exception/OptionFrozenException.php @@ -12,7 +12,7 @@ namespace Symfony\Component\OptionsResolver\Exception; /** - * Exception thrown when a frozen option is setted. + * Exception thrown when a frozen option is set. */ class OptionFrozenException extends InvalidArgumentException { diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index 8e73e502e4c16..63a92d6946d9d 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -420,7 +420,6 @@ public function getFrozenOptions() return array_keys($this->frozen); } - /** * Sets the normalizer for an option. * diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index 510cf12d8fc7c..2f9339a7906c8 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -403,7 +403,6 @@ public function testGetFrozenOptions() $this->assertEquals(array('foo', 'bar', 'baz'), $this->resolver->getFrozenOptions()); } - //////////////////////////////////////////////////////////////////////////// // setDefined()/isDefined()/getDefinedOptions() //////////////////////////////////////////////////////////////////////////// From d46984215088f756acc2712ea9240257f0f72dd4 Mon Sep 17 00:00:00 2001 From: unexge Date: Tue, 29 Dec 2015 19:57:08 +0200 Subject: [PATCH 3/6] only assigned options can be frozen --- .../MissingDefaultValueException.php | 19 +++++++++++++++++++ .../OptionsResolver/OptionsResolver.php | 8 ++++++++ .../Tests/OptionsResolverTest.php | 14 +++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/OptionsResolver/Exception/MissingDefaultValueException.php diff --git a/src/Symfony/Component/OptionsResolver/Exception/MissingDefaultValueException.php b/src/Symfony/Component/OptionsResolver/Exception/MissingDefaultValueException.php new file mode 100644 index 0000000000000..e1c3358dec647 --- /dev/null +++ b/src/Symfony/Component/OptionsResolver/Exception/MissingDefaultValueException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\OptionsResolver\Exception; + +/** + * Exception thrown when a unassigned option trying to be freeze. + */ +class MissingDefaultValueException extends InvalidArgumentException +{ +} diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index 63a92d6946d9d..62ad89ba6c5e7 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -13,6 +13,7 @@ use Symfony\Component\OptionsResolver\Exception\AccessException; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; +use Symfony\Component\OptionsResolver\Exception\MissingDefaultValueException; use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; use Symfony\Component\OptionsResolver\Exception\NoSuchOptionException; use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException; @@ -390,6 +391,13 @@ public function setFrozen($optionNames) } foreach ((array) $optionNames as $option) { + if (!$this->hasDefault($option)) { + throw new MissingDefaultValueException(sprintf( + 'The option "%s" has not a default value. You can not freeze it.', + $option + )); + } + $this->frozen[$option] = true; } diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index 2f9339a7906c8..f21cbdef25342 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -389,20 +389,32 @@ public function testFailIfFrozenOptionSetted() public function testIsFrozen() { - $this->assertFalse($this->resolver->isFrozen('foo')); + $this->resolver->setDefault('foo', 'bar'); $this->resolver->setFrozen('foo'); + $this->assertTrue($this->resolver->isFrozen('foo')); + $this->assertFalse($this->resolver->isFrozen('bar')); } public function testGetFrozenOptions() { $this->assertEquals(array(), $this->resolver->getFrozenOptions()); + $this->resolver->setDefaults(array('foo' => 1, 'bar' => 2, 'baz' => 3)); $this->resolver->setFrozen(array('foo', 'bar', 'baz')); $this->assertEquals(array('foo', 'bar', 'baz'), $this->resolver->getFrozenOptions()); } + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\MissingDefaultValueException + * @expectedExceptionMessage The option "foo" has not a default value. You can not freeze it. + */ + public function testFailIfUnassignedOptionTryingToFrozen() + { + $this->resolver->setFrozen('foo'); + } + //////////////////////////////////////////////////////////////////////////// // setDefined()/isDefined()/getDefinedOptions() //////////////////////////////////////////////////////////////////////////// From 0c2b48ce09ea08b514c878cbccdfb57b3fa12b1e Mon Sep 17 00:00:00 2001 From: unexge Date: Wed, 30 Dec 2015 20:30:44 +0200 Subject: [PATCH 4/6] fix typo --- src/Symfony/Component/OptionsResolver/OptionsResolver.php | 8 ++++---- .../OptionsResolver/Tests/OptionsResolverTest.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index 62ad89ba6c5e7..b514a77864bf2 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -387,13 +387,13 @@ public function getDefinedOptions() public function setFrozen($optionNames) { if ($this->locked) { - throw new AccessException('Options cannot be freeze from a lazy option or normalizer.'); + throw new AccessException('Options cannot be frozen from a lazy option or normalizer.'); } foreach ((array) $optionNames as $option) { if (!$this->hasDefault($option)) { throw new MissingDefaultValueException(sprintf( - 'The option "%s" has not a default value. You can not freeze it.', + 'The option "%s" has no default value. You cannot freeze it.', $option )); } @@ -721,7 +721,7 @@ public function clear() * @return array The merged and validated options * * @throws UndefinedOptionsException If an option name is undefined - * @throws OptionFrozenException If a frozen option is setted + * @throws OptionFrozenException If a frozen option is set * @throws InvalidOptionsException If an option doesn't fulfill the * specified validation rules * @throws MissingOptionsException If a required option is missing @@ -757,7 +757,7 @@ public function resolve(array $options = array()) foreach ($options as $option => $value) { if (isset($this->frozen[$option])) { throw new OptionFrozenException(sprintf( - 'The option "%s" is frozen. You cannot change it\'s value.', + 'The option "%s" is frozen. You cannot change its value.', $option )); } diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index f21cbdef25342..a0dad43455f5c 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -377,7 +377,7 @@ public function testGetMissingOptions() /** * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionFrozenException - * @expectedExceptionMessage The option "foo" is frozen. You cannot change it's value. + * @expectedExceptionMessage The option "foo" is frozen. You cannot change its value. */ public function testFailIfFrozenOptionSetted() { @@ -408,7 +408,7 @@ public function testGetFrozenOptions() /** * @expectedException \Symfony\Component\OptionsResolver\Exception\MissingDefaultValueException - * @expectedExceptionMessage The option "foo" has not a default value. You can not freeze it. + * @expectedExceptionMessage The option "foo" has no default value. You cannot freeze it. */ public function testFailIfUnassignedOptionTryingToFrozen() { From 81d43bac91d60422411424ae70b117b1bd37b4cb Mon Sep 17 00:00:00 2001 From: unexge Date: Wed, 30 Dec 2015 20:41:36 +0200 Subject: [PATCH 5/6] cannot change default value of the frozen option --- .../Component/OptionsResolver/OptionsResolver.php | 7 +++++++ .../OptionsResolver/Tests/OptionsResolverTest.php | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index b514a77864bf2..d7337b8594d6a 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -167,6 +167,13 @@ public function setDefault($option, $value) throw new AccessException('Default values cannot be set from a lazy option or normalizer.'); } + if ($this->isFrozen($option)) { + throw new OptionFrozenException(sprintf( + 'The option "%s" is frozen. You cannot change its default value.', + $option + )); + } + // If an option is a closure that should be evaluated lazily, store it // in the "lazy" property. if ($value instanceof \Closure) { diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index a0dad43455f5c..3c36052b4817a 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -415,6 +415,17 @@ public function testFailIfUnassignedOptionTryingToFrozen() $this->resolver->setFrozen('foo'); } + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\OptionFrozenException + * @expectedExceptionMessage The option "foo" is frozen. You cannot change its default value. + */ + public function testFailIfTryingToSetDefaultForFrozenOption() + { + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setFrozen('foo'); + $this->resolver->setDefault('foo', 'baz'); + } + //////////////////////////////////////////////////////////////////////////// // setDefined()/isDefined()/getDefinedOptions() //////////////////////////////////////////////////////////////////////////// From 548cf8e1642d2f107c16219407154886ff77bf57 Mon Sep 17 00:00:00 2001 From: unexge Date: Fri, 8 Jan 2016 20:59:28 +0200 Subject: [PATCH 6/6] unnecessary phpdoc removed --- src/Symfony/Component/OptionsResolver/OptionsResolver.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index d7337b8594d6a..8e30c249fae1e 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -427,8 +427,6 @@ public function isFrozen($option) * Returns the names of all frozen options. * * @return string[] The names of the frozen options - * - * @see isFrozen() */ public function getFrozenOptions() {