diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index 0feeeddfa7..4605822ad3 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -47,6 +47,12 @@ class OptionsResolver */ private $allowedValues = array(); + /** + * A list of filters transforming each resolved options. + * @var array + */ + private $filters = array(); + /** * Creates a new instance. */ @@ -58,12 +64,23 @@ class OptionsResolver /** * Sets default option values. * - * @param array $defaultValues A list of option names as keys and default values - * as values. The option values may be closures - * of the following signatures: + * The options can either be values of any types or closures that + * evaluate the option value lazily. These closures must have one + * of the following signatures: * - * - function (Options $options) - * - function (Options $options, $previousValue) + * + * function (Options $options) + * function (Options $options, $value) + * + * + * The second parameter passed to the closure is the previously + * set default value, in case you are overwriting an existing + * default value. + * + * The closures should return the lazily created option value. + * + * @param array $defaultValues A list of option names as keys and default + * values or closures as values. * * @return OptionsResolver The resolver instance. */ @@ -81,16 +98,13 @@ class OptionsResolver /** * Replaces default option values. * - * Old defaults are erased, which means that closures passed here can't + * Old defaults are erased, which means that closures passed here cannot * access the previous default value. This may be useful to improve * performance if the previous default value is calculated by an expensive * closure. * - * @param array $defaultValues A list of option names as keys and default values - * as values. The option values may be closures - * of the following signature: - * - * - function (Options $options) + * @param array $defaultValues A list of option names as keys and default + * values or closures as values. * * @return OptionsResolver The resolver instance. */ @@ -208,6 +222,32 @@ class OptionsResolver return $this; } + /** + * Sets filters that are applied on resolved options. + * + * The filters should be closures with the following signature: + * + * + * function (Options $options, $value) + * + * + * The second parameter passed to the closure is the value of + * the option. + * + * The closure should return the filtered value. + * + * @param array $filters + * @return OptionsResolver + */ + public function setFilters(array $filters) + { + $this->validateOptionsExistence($filters); + + $this->filters = array_replace($this->filters, $filters); + + return $this; + } + /** * Returns whether an option is known. * @@ -264,6 +304,11 @@ class OptionsResolver $combinedOptions->set($option, $value); } + // Apply filters + foreach ($this->filters as $option => $filter) { + $combinedOptions->overload($option, $filter); + } + // Resolve options $resolvedOptions = $combinedOptions->all(); diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php similarity index 92% rename from src/Symfony/Component/OptionsResolver/Tests/OptionResolverTest.php rename to src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index ef68c7f1e1..76d1611a8b 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -373,6 +373,36 @@ class OptionsResolverTest extends \PHPUnit_Framework_TestCase $this->assertFalse($this->resolver->isRequired('foo')); } + public function testFiltersTransformFinalOptions() + { + $this->resolver->setDefaults(array( + 'foo' => 'bar', + 'bam' => 'baz', + )); + $this->resolver->setFilters(array( + 'foo' => function (Options $options, $value) { + return $options['bam'] . '[' . $value . ']'; + }, + )); + + $expected = array( + 'foo' => 'baz[bar]', + 'bam' => 'baz', + ); + + $this->assertEquals($expected, $this->resolver->resolve(array())); + + $expected = array( + 'foo' => 'boo[custom]', + 'bam' => 'boo', + ); + + $this->assertEquals($expected, $this->resolver->resolve(array( + 'foo' => 'custom', + 'bam' => 'boo', + ))); + } + public function testResolveWithoutOptionSucceedsIfRequiredAndDefaultValue() { $this->resolver->setRequired(array(