diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index d6554baa0a2ff..772a743d975cd 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -214,9 +214,18 @@ public function isRequired($option) /** * {@inheritdoc} */ - public function resolve(array $options = array()) + public function resolve(array $options = array(), $flags = 0) { - $this->validateOptionsExistence($options); + if (($flags & OptionsResolverInterface::REMOVE_UNKNOWN) && ($flags & OptionsResolverInterface::IGNORE_UNKNOWN)) { + throw new \InvalidArgumentException('OptionsResolverInterface::REMOVE_UNKNOWN and OptionsResolverInterface::IGNORE_UNKNOWN are mutually exclusive'); + } + + if ($flags & OptionsResolverInterface::REMOVE_UNKNOWN) { + $options = $this->removeUnknownOptions($options); + } elseif (!($flags & OptionsResolverInterface::IGNORE_UNKNOWN)) { + $this->validateOptionsExistence($options); + } + $this->validateOptionsCompleteness($options); // Make sure this method can be called multiple times @@ -236,11 +245,23 @@ public function resolve(array $options = array()) return $resolvedOptions; } + /** + * Remove unknown options + * + * @param array $options A list of option names as keys. + * + * @return array Options with all unknown options removed + */ + private function removeUnknownOptions(array $options) + { + return array_intersect_key($options, $this->knownOptions); + } + /** * Validates that the given option names exist and throws an exception * otherwise. * - * @param array $options An list of option names as keys. + * @param array $options A list of option names as keys. * * @throws InvalidOptionsException If any of the options has not been defined. */ @@ -264,7 +285,7 @@ private function validateOptionsExistence(array $options) * Validates that all required options are given and throws an exception * otherwise. * - * @param array $options An list of option names as keys. + * @param array $options A list of option names as keys. * * @throws MissingOptionsException If a required option is missing. */ diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolverInterface.php b/src/Symfony/Component/OptionsResolver/OptionsResolverInterface.php index 8474c4bcd793d..e5a1f1e591c89 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolverInterface.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolverInterface.php @@ -16,6 +16,18 @@ */ interface OptionsResolverInterface { + /** + * Remove unknown options passed to the resolve() method + * Is mutually exclusive with IGNORE_UNKNOWN + */ + const REMOVE_UNKNOWN = 1; + + /** + * Ignore unknown options passed to the resolve() method + * Is mutually exclusive with REMOVE_UNKNOWN + */ + const IGNORE_UNKNOWN = 2; + /** * Sets default option values. * @@ -196,6 +208,7 @@ public function isRequired($option); * Returns the combination of the default and the passed options. * * @param array $options The custom option values. + * @param int $flags Can be REMOVE_UNKNOWN or IGNORE_UNKNOWN * * @return array A list of options and their values. * @@ -206,5 +219,5 @@ public function isRequired($option); * @throws Exception\OptionDefinitionException If a cyclic dependency is detected * between two lazy options. */ - public function resolve(array $options = array()); + public function resolve(array $options = array(), $flags = 0); } diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index d50cd3fcfe3e4..e7b4b1b9de47c 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\OptionsResolver\Tests; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\Options; @@ -678,4 +679,52 @@ public function testClone() 'three' => '3', ), $clone->resolve()); } + + /** + * @expectedException \InvalidArgumentException + */ + public function testRemoveUnknownAndIgnoreUnknownAreMutuallyExclusive() + { + $this->resolver->resolve(array( + 'one' => 'one', + 'two' => 'two' + ), OptionsResolverInterface::REMOVE_UNKNOWN | OptionsResolverInterface::IGNORE_UNKNOWN); + } + + public function testRemoveUnknownOption() + { + $this->resolver->setDefaults(array( + 'one' => 'default', + 'two' => 'default' + )); + + $options = $this->resolver->resolve(array( + 'one' => 'keep', + 'three' => 'remove' + ), OptionsResolverInterface::REMOVE_UNKNOWN); + + $this->assertEquals($options, array( + 'one' => 'keep', + 'two' => 'default' + )); + } + + public function testIgnoreUnknownOption() + { + $this->resolver->setDefaults(array( + 'one' => 'default', + 'two' => 'default' + )); + + $options = $this->resolver->resolve(array( + 'one' => 'keep', + 'three' => 'ignored' + ), OptionsResolverInterface::IGNORE_UNKNOWN); + + $this->assertEquals($options, array( + 'one' => 'keep', + 'two' => 'default', + 'three' => 'ignored' + )); + } }