Description
The normalization procedure is the last step of the option resolution algorithm, it allow us to change the default or passed value after validating it.
Problem
Currently, we have the possibility to configure only one normalizer per option. For example, this is a form type definition that belongs to a third-party package:
class Type1 extends AbstractType
{
private $dummy;
public function __construct(Dummy $dummy)
{
$this->dummy = $dummy;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('foo', null);
$resolver->setAllowedTypes('foo', ['null', 'callable']);
$resolver->setNormalizer('foo', function (Options $options, $foo) {
if (\is_callable($foo)) {
$foo = $foo($this->dummy);
}
return $foo;
});
}
}
Note that the dummy
instance is used in the normalizer closure.
Next, we want to create a custom form type (in app context) named Type2
, that extend from Type1
using getParent()
method and it need to add an extra allowed type + normalization to the foo
option:
class Type2 extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->addAllowedTypes('foo', 'string');
$resolver->setNormalizer('foo', function (Options $options, $foo) {
if (\is_string($foo)) {
$foo = FooFactory::fromString($foo);
}
return $foo;
});
}
public function getParent()
{
return Type1::class;
}
}
At this point, the code is incorrect, because the parent normalizer of the foo
option has been overridden and the ability to normalize a callable is lost.
As workaround, we can copy the parent code and all internal deps (e.g. dummy
service), but clearly this is a case that should be improved.
That's why I propose the following.
Proposal
Introduce a new addNormalizer()
method that allows us to add more than one normalization function associated with an option (just like lazy defaults now work).
Signature:
public function addNormalizer(string $option, \Closure $normalizer): self
Later, the solution to the above problem will be to use addNormalizer()
instead of setNormalizer()
in Type2
, receiving $foo
value already normalized by the parent type.
WDYT?
I've reviewed the Component code to analyze its implementation feasibility and it look good to me (draft ready yceruto@c5353a2)