Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[RFC][OptionsResolver] Add a new "addNormalizer()" method and normalization hierarchy #30310

Copy link
Copy link
Closed
@yceruto

Description

@yceruto
Issue body actions

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)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.