Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OptionsResolver] Add a new method addNormalizer and normalization hierarchy #30371

Merged
merged 1 commit into from Mar 31, 2019

Conversation

Projects
None yet
6 participants
@yceruto
Copy link
Contributor

commented Feb 24, 2019

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #30310
License MIT
Doc PR symfony/symfony-docs#11103

3rd-party package

Given: (CLICK ME)

Generic type:

class FooType extends AbstractType
{
    private $registry;

    public function __construct(ManagerRegistry $registry)
    {
        $this->registry = $registry;
    }

    // buildForm ...

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setRequired('class');
        $resolver->setDefaults([
            'em' => null,
            'query' => null,
        ]);
        $resolver->setAllowedTypes('em', ['null', 'string']);
        $resolver->setAllowedTypes('query', ['null', 'callable']);

        $resolver->setNormalizer('em', function (Options $options, $em) {
            if (null !== $em) {
                return $this->registry->getManager($em);
            }

            return $this->registry->getManagerForClass($options['class']);
        });

        $resolver->setNormalizer('query', function (Options $options, $query) {
            if (\is_callable($query)) {
                $query = $query($options['em']->getRepository($options['class']));

                if (!$query instanceof Query) {
                    throw new UnexpectedTypeException($query, 'Doctrine\ORM\Query');
                }
            }

            return $query;
        });
    }
}

App context

Before (CLICK ME)

Normalizing the new allowed value will require to override the parent's normalizer:

class BarType extends AbstractType
{
    private $registry;

    public function __construct(ManagerRegistry $registry)
    {
        $this->registry = $registry;
    }

    // buildForm ...

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->addAllowedTypes('em', 'Doctrine\ORM\EntityManagerInterface');

        $resolver->setNormalizer('em', function (Options $options, $em) {
            if ($em instanceof EntityManagerInterface) {
                return $em;
            }

            if (null !== $em) {
                return $this->registry->getManager($em);
            }

            return $this->registry->getManagerForClass($options['class']);
        });

        $resolver->addAllowedTypes('query', 'string');

        $resolver->setNormalizer('query', function (Options $options, $query) {
            if (\is_callable($query)) {
                $query = $query($options['em']->getRepository($options['class']));

                if (!$query instanceof Query) {
                    throw new UnexpectedTypeException($query, 'Doctrine\ORM\Query');
                }
            }

            if (\is_string($query)) {
                $query = $options['em']->createQuery($query);
            }

            return $query;
        });
    }

    public function getParent()
    {
        return FooType::class;
    }
}

After (CLICK ME)

The new normalizer is added to the stack and it'll receive the previously normalized value or if forcePrepend = true the validated value:

class BarType extends AbstractType
{
    // buildForm ...

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->addAllowedTypes('em', 'Doctrine\ORM\EntityManagerInterface');

        $resolver->addNormalizer('em', function (Options $options, $em) {
            if ($em instanceof EntityManagerInterface) {
                return $em;
            }

            return $em;
        }, true); // $forcePrepend = true (3rd argument)

        $resolver->addAllowedTypes('query', 'string');

        $resolver->addNormalizer('query', function (Options $options, $query) {
            if (\is_string($query)) {
                $query = $options['em']->createQuery($query);
            }

            return $query;
        });
    }

    public function getParent()
    {
        return FooType::class;
    }
}

@yceruto yceruto force-pushed the yceruto:add_normalizer branch from 9621750 to d280f5b Feb 24, 2019

@yceruto

This comment has been minimized.

Copy link
Contributor Author

commented Feb 24, 2019

@yceruto

This comment has been minimized.

Copy link
Contributor Author

commented Feb 27, 2019

It seems that our friend @carsonbot was not working 3 days ago :)

Status: Needs review

@yceruto yceruto force-pushed the yceruto:add_normalizer branch from d280f5b to d9ae6c8 Mar 4, 2019

@yceruto

This comment has been minimized.

Copy link
Contributor Author

commented Mar 7, 2019

@nicolas-grekas comments addressed, thanks!

@yceruto

This comment has been minimized.

Copy link
Contributor Author

commented Mar 7, 2019

Adding doc PR reference symfony/symfony-docs#11103

@yceruto

This comment has been minimized.

Copy link
Contributor Author

commented Mar 27, 2019

BTW missing OptionsResolver label :)

@fabpot

fabpot approved these changes Mar 31, 2019

@fabpot fabpot force-pushed the yceruto:add_normalizer branch from a600fbe to cf41254 Mar 31, 2019

@fabpot

This comment has been minimized.

Copy link
Member

commented Mar 31, 2019

Thank you @yceruto.

@fabpot fabpot merged commit cf41254 into symfony:master Mar 31, 2019

1 of 3 checks passed

continuous-integration/appveyor/pr Waiting for AppVeyor build to complete
Details
continuous-integration/travis-ci/pr The Travis CI build is in progress
Details
fabbot.io Your code looks good.
Details

fabpot added a commit that referenced this pull request Mar 31, 2019

feature #30371 [OptionsResolver] Add a new method addNormalizer and n…
…ormalization hierarchy (yceruto)

This PR was squashed before being merged into the 4.3-dev branch (closes #30371).

Discussion
----------

[OptionsResolver] Add a new method addNormalizer and normalization hierarchy

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #30310
| License       | MIT
| Doc PR        | symfony/symfony-docs#11103

### 3rd-party package

<details><summary>Given: (CLICK ME)</summary>
<p>

Generic type:
```php
class FooType extends AbstractType
{
    private $registry;

    public function __construct(ManagerRegistry $registry)
    {
        $this->registry = $registry;
    }

    // buildForm ...

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setRequired('class');
        $resolver->setDefaults([
            'em' => null,
            'query' => null,
        ]);
        $resolver->setAllowedTypes('em', ['null', 'string']);
        $resolver->setAllowedTypes('query', ['null', 'callable']);

        $resolver->setNormalizer('em', function (Options $options, $em) {
            if (null !== $em) {
                return $this->registry->getManager($em);
            }

            return $this->registry->getManagerForClass($options['class']);
        });

        $resolver->setNormalizer('query', function (Options $options, $query) {
            if (\is_callable($query)) {
                $query = $query($options['em']->getRepository($options['class']));

                if (!$query instanceof Query) {
                    throw new UnexpectedTypeException($query, 'Doctrine\ORM\Query');
                }
            }

            return $query;
        });
    }
}
```
</p>
</details>

### App context

<details><summary>Before (CLICK ME)</summary>
<p>

Normalizing the new allowed value will require to override the parent's normalizer:
```php
class BarType extends AbstractType
{
    private $registry;

    public function __construct(ManagerRegistry $registry)
    {
        $this->registry = $registry;
    }

    // buildForm ...

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->addAllowedTypes('em', 'Doctrine\ORM\EntityManagerInterface');

        $resolver->setNormalizer('em', function (Options $options, $em) {
            if ($em instanceof EntityManagerInterface) {
                return $em;
            }

            if (null !== $em) {
                return $this->registry->getManager($em);
            }

            return $this->registry->getManagerForClass($options['class']);
        });

        $resolver->addAllowedTypes('query', 'string');

        $resolver->setNormalizer('query', function (Options $options, $query) {
            if (\is_callable($query)) {
                $query = $query($options['em']->getRepository($options['class']));

                if (!$query instanceof Query) {
                    throw new UnexpectedTypeException($query, 'Doctrine\ORM\Query');
                }
            }

            if (\is_string($query)) {
                $query = $options['em']->createQuery($query);
            }

            return $query;
        });
    }

    public function getParent()
    {
        return FooType::class;
    }
}
```
</p>
</details>

<details><summary>After (CLICK ME)</summary>
<p>

The new normalizer is added to the stack and it'll receive the previously normalized value or if `forcePrepend = true` the validated value:
```php
class BarType extends AbstractType
{
    // buildForm ...

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->addAllowedTypes('em', 'Doctrine\ORM\EntityManagerInterface');

        $resolver->addNormalizer('em', function (Options $options, $em) {
            if ($em instanceof EntityManagerInterface) {
                return $em;
            }

            return $em;
        }, true); // $forcePrepend = true (3rd argument)

        $resolver->addAllowedTypes('query', 'string');

        $resolver->addNormalizer('query', function (Options $options, $query) {
            if (\is_string($query)) {
                $query = $options['em']->createQuery($query);
            }

            return $query;
        });
    }

    public function getParent()
    {
        return FooType::class;
    }
}
```
</p>
</details>

Commits
-------

cf41254 [OptionsResolver] Add a new method addNormalizer and normalization hierarchy

@yceruto yceruto deleted the yceruto:add_normalizer branch Mar 31, 2019

javiereguiluz added a commit to symfony/symfony-docs that referenced this pull request Apr 5, 2019

minor #11103 [OptionsResolver] Documenting the new addNormalizer meth…
…od (yceruto)

This PR was merged into the master branch.

Discussion
----------

[OptionsResolver] Documenting the new addNormalizer method

symfony/symfony#30371

Commits
-------

a2e6c2a Documenting the new method addNormalizer in OptionsResolver component

fabpot added a commit that referenced this pull request Apr 15, 2019

feature #31082 [Form] Show all option normalizers on debug:form comma…
…nd (yceruto)

This PR was merged into the 4.3-dev branch.

Discussion
----------

[Form] Show all option normalizers on debug:form command

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT

Follow-up #30371

![normalizers](https://user-images.githubusercontent.com/2028198/55996454-6667df80-5c85-11e9-94f6-9ee3988833f3.png)

Commits
-------

f1d3bc0 Show all option normalizers on debug:form command

@nicolas-grekas nicolas-grekas modified the milestones: next, 4.3 Apr 30, 2019

@fabpot fabpot referenced this pull request May 9, 2019

Merged

Release v4.3.0-BETA1 #31435

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.