Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[WIP] [Serializer] Allow deserializing union types properly #45824

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

Closed
wants to merge 9,180 commits into from
Closed

[WIP] [Serializer] Allow deserializing union types properly #45824

wants to merge 9,180 commits into from

Conversation

T-bond
Copy link
Contributor

@T-bond T-bond commented Mar 22, 2022

Q A
Branch? 4.4
Bug fix? yes
New feature? no
Deprecations? no
Tickets #45818
License MIT
Doc PR -

I tried to implement the proper fix, that I mentioned in my issue.

94noni and others added 30 commits January 26, 2022 16:39
…rt (94noni)

This PR was submitted for the 5.4 branch but it was squashed and merged into the 5.3 branch instead.

Discussion
----------

[Notifier] Fix encoding of messages with FreeMobileTransport

| Q             | A
| ------------- | ---
| Branch?       | 5.3
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix sending accents chars
| License       | MIT

When I first [introduce this transport](#35690) I used to test it with basic text, now with some French accent I need this fix otherwise the accent chars are not sent

Commits
-------

5760694 [Notifier] Fix encoding of messages with FreeMobileTransport
…pseudo type false (Thomas Nunninger)

This PR was squashed before being merged into the 5.3 branch.

Discussion
----------

[Serializer] Fix AbstractObjectNormalizer not considering pseudo type false

| Q             | A
| ------------- | ---
| Branch?       | 5.3
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #45151
| License       | MIT
| Doc PR        |

AbstractObjectNormalizer does not consider pseudo type false (bug #45151)

When you have a PHP 8.0 object where an attribute uses the pseudo type false (in a union type) you can't denormalize an array to that object.

Commits
-------

27d9eff [Serializer] Fix AbstractObjectNormalizer not considering pseudo type false
* 4.4:
  [Cache] workaround PHP crash
  [Console] Fix PHP 8.1 deprecation in ChoiceQuestion
  Making the parser stateless
* 4.4:
  [Form] UrlType should not add protocol to emails
  Silence isatty warnings during tty detection
  Replaced full CoC text with link to documentation
… array (derrabus)

This PR was merged into the 5.3 branch.

Discussion
----------

[Validator] Fix Choice constraint with associative choices array

| Q             | A
| ------------- | ---
| Branch?       | 5.3
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #41508
| License       | MIT
| Doc PR        | N/A

This PR moves the `$options` parameter to the beginning of the constructor signature in order to fix the scenario described in #41508.

I assume that the supported ways to construct this class are either an ordered arguments call with exactly one argument or a named argument call with zero or one ordered arguments. Those scenarios should continue to work and are covered with additional tests now.

However, an ordered arguments call to the constructor with at least two parameters would break after this change.

Commits
-------

ccd85fe Fix Choice constraint with associative choices array
* 5.3:
  Fix Choice constraint with associative choices array
  [Form] UrlType should not add protocol to emails
  Silence isatty warnings during tty detection
  [Serializer] Fix AbstractObjectNormalizer not considering pseudo type false
  [Notifier] Fix encoding of messages with FreeMobileTransport
  [Cache] workaround PHP crash
  [Console] Fix PHP 8.1 deprecation in ChoiceQuestion
  [Notifier] smsapi-notifier - correct encoding
  Replaced full CoC text with link to documentation
  Making the parser stateless
  [Console] fix restoring stty mode on CTRL+C
  fix merge (bis)
  fix merge
  [Process] Avoid calling fclose on an already closed resource
  [GHA] test tty group
  [DI] Fix tests on PHP 7.1
This PR was merged into the 5.4 branch.

Discussion
----------

[DoctrineBridge] [5.4] Fix automapping

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #44355
| License       | MIT
| Doc PR        | N/A

This should fix the broken automapping configuration for bundles that use annotations and attributes, see #44355 for additional details.

When using the newer bundle directory structure conventions, especially with the `Bundle::getPath()` method overridden to point the bundle root path to the Bundle class' parent directory, the issue comes up because the bundle filesystem root path does not match the root path for the actual bundle code (effectively the PSR-4 root path).

To fix automapping, the `AbstractDoctrineExtension::detectMetadataDriver()` method will be called a second time with the Bundle classpath if the first call (which is effectively the same as `Bundle::getPath()`)  can't resolve the appropriate mapping type.  This will also update setting `$bundleConfig['dir']` for drivers that are based on PHP classes so that the root path is based on the bundle classpath (AKA the PSR-4 root path) instead of the bundle path.

The bulk of this patch is mainly from adding test fixture bundles to be able to test the `AbstractDoctrineExtension::getMappingDriverBundleConfigDefaults()` method in this repo and ensuring that the metadata driver detection works right for all of the supported drivers.

Commits
-------

0aaa2fd Fix bundle automapping detection for annotations and attributes
…s to suggest migrating (stof)

This PR was squashed before being merged into the 5.4 branch.

Discussion
----------

[Yaml] Improve the deprecation warnings for octal numbers to suggest migrating

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | no
| New feature?  | no
| Deprecations? | no
| Tickets       |
| License       | MIT
| Doc PR        | n/a

The existing deprecation messages made some people think that octal numbers are totally unsupported in newer Symfony versions (see thephpleague/flysystem-bundle#81). This updates the deprecation message to provide the alternative when using an octal number is intended, to migrate to the Yaml 1.2 way of representing them.

Commits
-------

4153af6 [Yaml] Improve the deprecation warnings for octal numbers to suggest migrating
…ectory (julienfalque)

This PR was squashed before being merged into the 5.4 branch.

Discussion
----------

[Finder] Fix finding VCS re-included files in excluded directory

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | #45048
| License       | MIT
| Doc PR        | -

This PR fixes a bug where `Finder` would not return a file inside a directory when gitignore rules exclude the directory but re-include the file.

The first commit makes `Finder` return the file. Though, as shown by the second commit, the directory is still not returned. Strictly speaking, the directory *is* ignored, so in some sense `Finder` is correct. But then it contains a file that is not ignored. In this case, Git would see the directory anyway. Should `Finder` return any ignored directory as soon as it contains a file that is not ignored? Even if that file is not part of `Finder` results?

Commits
-------

d108ac5 [Finder] Fix finding VCS re-included files in excluded directory
…he env key already exists (fancyweb)

This PR was merged into the 5.4 branch.

Discussion
----------

[Dotenv] Fix bootEnv() override with .env.local.php when the env key already exists

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

If `$_SERVER['APP_ENV'] = 'foo'` and `.env.local.php` exists and returns `'APP_ENV' => 'prod'`, the override does not work.

Commits
-------

1f29087 [Dotenv] Fix bootEnv() override with .env.local.php when the env key already exists
* 5.4: (21 commits)
  [Finder] Fix finding VCS re-included files in excluded directory
  [Yaml] Improve the deprecation warnings for octal numbers to suggest migrating
  Fix Choice constraint with associative choices array
  [Form] UrlType should not add protocol to emails
  [Dotenv] Fix bootEnv() override with .env.local.php when the env key already exists
  Silence isatty warnings during tty detection
  [Serializer] Fix AbstractObjectNormalizer not considering pseudo type false
  [Notifier] Fix encoding of messages with FreeMobileTransport
  [Cache] workaround PHP crash
  [Console] Fix PHP 8.1 deprecation in ChoiceQuestion
  [HttpKernel] Fix compatibility with php bridge and already started php sessions
  [Notifier] smsapi-notifier - correct encoding
  Replaced full CoC text with link to documentation
  Making the parser stateless
  [Console] fix restoring stty mode on CTRL+C
  fix merge (bis)
  fix merge
  [Process] Avoid calling fclose on an already closed resource
  [GHA] test tty group
  [DI] Fix tests on PHP 7.1
  ...
…ancyweb)

This PR was merged into the 5.4 branch.

Discussion
----------

[Runtime] Fix --env and --no-debug with dotenv_overload

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

With the `dotenv_overload` option enabled, commands `--no-debug` and `--env=prod` options are not honored.

Commits
-------

0460f81 [Runtime] Fix --env and --no-debug with dotenv_overload
* 5.4:
  [Runtime] Fix --env and --no-debug with dotenv_overload
  cs fix
…on default context is bound (ArnoudThibaut)

This PR was squashed before being merged into the 5.4 branch.

Discussion
----------

[FrameworkBundle] Fix missing arguments when a serialization default context is bound

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #44960
| License       | MIT

I used `null` as first argument for `JsonSerializableNormalizer` definition even if a service exist for the `ClassMetadataFactoryInterface` to keep the actual behavior

Commits
-------

1855798 [FrameworkBundle] Fix missing arguments when a serialization default context is bound
…er-schranz)

This PR was submitted for the 6.0 branch but it was squashed and merged into the 5.4 branch instead.

Discussion
----------

[HttpKernel] Fix session test cases for symfony

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

Related to: #44634

Fix HttpKernel test cases as session are created differently in symfony 6.0.

Commits
-------

b047a2d [HttpKernel] Fix session test cases for symfony
* 5.4:
  [DoctrineBridge] fix tests
  [HttpKernel] Fix session test cases for symfony
  [FrameworkBundle] Fix missing arguments when a serialization default context is bound
nicolas-grekas and others added 6 commits March 22, 2022 16:31
* 4.4:
  [Cache] Declaratively declare/hide DoctrineProvider to avoid breaking static analysis
  [HttpClient] Let curl handle Content-Length headers
  Improve testsuite
  [HttpClient] Move Content-Type after Content-Length
  [HttpClient] minor cs fix
This PR was merged into the 5.4 branch.

Discussion
----------

[Config] Fix using null values with config builders

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #45782
| License       | MIT
| Doc PR        | -

The generated config builders will no longer discard `null` values.

Commits
-------

1264225 [Config] Fix using null values with config builders
The `--only-missing` and `--only-unused` options should be independent of
each other.

When using the `--only-missing` option, only **missing** messages
should be relevant to the outcome of the execution. If there are no
missing messages, but some unused messages, the execution of the command
was still successful and no non-zero exit code should be returned.

The same applies when using the `--only-unused` option. In this case,
only **unused** messages should be relevant to the execution result,
even if there are some missing messages.
…and (gndk)

This PR was merged into the 5.4 branch.

Discussion
----------

[FrameworkBundle] Fix exit codes in debug:translation command

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

I noticed this bug while working on a CI job to check translations with `debug:translation --only-missing`. The output of the command was empty (no results in the table), so there were no missing messages. But the command still failed with non-zero exit code.

After a bit of investigation I noticed that there were no **missing** messages, but a few **unused** messages. And the command failed with the exit code for **unused** messages, despite running it with `--only-missing`. After confirming this as the problem, the fix was pretty straightforward.

The `--only-missing` and `--only-unused` options should be independent of each other.

When using the `--only-missing` option, only **missing** messages should be relevant to the outcome of the execution. If there are no missing messages, but some unused messages, the execution of the command was still successful and no non-zero exit code should be returned.

The same applies when using the `--only-unused` option. In this case, only **unused** messages should be relevant to the execution result, even if there are some missing messages.

Commits
-------

5439bf2 [FrameworkBundle] Fix exit codes in debug:translation command
* 4.4:
  Revert "bug #45813 [HttpClient] Move Content-Type after Content-Length (nicolas-grekas)"
* 5.4:
  Revert "bug #45813 [HttpClient] Move Content-Type after Content-Length (nicolas-grekas)"
  [FrameworkBundle] Fix exit codes in debug:translation command
  [Cache] Declaratively declare/hide DoctrineProvider to avoid breaking static analysis
  [HttpClient] Let curl handle Content-Length headers
  Improve testsuite
  [HttpClient] Move Content-Type after Content-Length
  [HttpClient] minor cs fix
  [Config] Fix using null values with config builders
@T-bond T-bond requested a review from dunglas as a code owner March 22, 2022 22:15
@carsonbot carsonbot added this to the 6.0 milestone Mar 22, 2022
Copy link
Contributor Author

@T-bond T-bond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self review done. All checks passed. PR was developed with TDD.
I have been using Symfony for 2 weeks only, so I hope I haven't missed anything.
This PR solves my problem mentioned in the issue.

Anyways, thanks for this great software!

Status: Reviewed

@carsonbot
Copy link

Hey!

I think @Th3Mouk has recently worked with this code. Maybe they can help review this?

Cheers!

Carsonbot

@T-bond T-bond changed the title Allow deserializing union types properly [Serializer] Allow deserializing union types properly Mar 23, 2022
@nicolas-grekas
Copy link
Member

nicolas-grekas commented Mar 24, 2022

I'm not sure about the patch. It'd make more sense to me to go with the following one.
Note that the issue exists on branch 5.4 so it's where it should be fixed.

--- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
@@ -479,14 +479,14 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
                         } elseif ('true' === $data || '1' === $data) {
                             $data = true;
                         } else {
-                            throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be bool ("%s" given).', $attribute, $currentClass, $data), $data, [Type::BUILTIN_TYPE_BOOL], $context['deserialization_path'] ?? null);
+                            continue 2;
                         }
                         break;
                     case Type::BUILTIN_TYPE_INT:
                         if (ctype_digit($data) || '-' === $data[0] && ctype_digit(substr($data, 1))) {
                             $data = (int) $data;
                         } else {
-                            throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be int ("%s" given).', $attribute, $currentClass, $data), $data, [Type::BUILTIN_TYPE_INT], $context['deserialization_path'] ?? null);
+                            continue 2;
                         }
                         break;
                     case Type::BUILTIN_TYPE_FLOAT:
@@ -494,11 +494,11 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
                             return (float) $data;
                         }
 
-                        return match ($data) {
-                            'NaN' => \NAN,
-                            'INF' => \INF,
-                            '-INF' => -\INF,
-                            default => throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be float ("%s" given).', $attribute, $currentClass, $data), $data, [Type::BUILTIN_TYPE_FLOAT], $context['deserialization_path'] ?? null),
+                        switch ($data) {
+                            case 'NaN': return \NAN;
+                            case 'INF': return \INF;
+                            case '-INF': return -\INF;
+                            default: continue 3;
                         };
                 }
             }

</details.

@nicolas-grekas nicolas-grekas modified the milestones: 6.0, 5.4 Mar 24, 2022
@T-bond
Copy link
Contributor Author

T-bond commented Mar 24, 2022

I'm not sure about the patch. It'd make more sense to me to go with the following one.

I think this will not solve the problem, as the exception is thrown from the DateTime normalizer, which tries denormalize false. Also, this would change the current specialised message, if the type is not an union one.

Anyways, if you say, that this is the way to go forward, I will do it this way, and only apply the try-catch block to the other denormalizations, where the exception is thrown from somewhere else.

Note that the issue exists on branch 5.4 so it's where it should be fixed.

Yeah, I forgot that you can use union types with docblock before php 8. I will rewrite to patch for the 5.4 branch, when we could determine the correct solution.

@nicolas-grekas
Copy link
Member

I think this will not solve the problem, as the exception is thrown from the DateTime normalizer

Hum indeed, then the issue should be fixed on 4.4, since apparently we don't handle union types there either.
Let's go with your approach.

Can you please rebase+retarget for 4.4?

@T-bond T-bond changed the base branch from 6.0 to 4.4 March 24, 2022 14:19
@T-bond T-bond changed the title [Serializer] Allow deserializing union types properly [WIP] [Serializer] Allow deserializing union types properly Mar 24, 2022
@T-bond T-bond closed this Mar 24, 2022
@T-bond T-bond deleted the ticket_45818 branch March 24, 2022 14:52
nicolas-grekas added a commit that referenced this pull request Mar 24, 2022
This PR was merged into the 4.4 branch.

Discussion
----------

[Serializer] Fix denormalizing union types

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | Fix #45818
| License       | MIT
| Doc PR        | -
<!--
Replace this notice by a short README for your feature/bugfix.
This will help reviewers and should be a good start for the documentation.

Additionally (see https://symfony.com/releases):
 - Always add tests and ensure they pass.
 - Bug fixes must be submitted against the lowest maintained branch where they apply
   (lowest branches are regularly merged to upper ones so they get the fixes too.)
 - Features and deprecations must be submitted against the latest branch.
 - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry
 - Never break backward compatibility (see https://symfony.com/bc).
-->
`@nicolas`-grekas Replaces: #45824 as I accidentally registerred a lot of people to the notifier list when changing target branch.

Note about difference between docblock vs PHP 8 union types:
With PHP 8 union types, the resolved `$types` array was always (when I checked) in the same order, no matter the type definition.
So these two things: ```public null|boolean|DateTime``` and ```public DateTime|boolean|null``` would **always** generate an array, where the **first** item was `DateTime`.

With PHP docblock the `$tpyes` array order depends of the order of the documentation.
So the `* `@var` \DateTime|bool|null` would resolve to an array with `DateTime` as **first** item, but the `* `@var` null|bool|\DateTime` would resolve to the `DateTime` being the **last** element.

Commits
-------

98acd62 [Serializer] Fix denormalizing union types
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.