Skip to content

[Serializer] Allow default group in serialization context #44035

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

Conversation

noemi-salaun
Copy link
Contributor

@noemi-salaun noemi-salaun commented Nov 13, 2021

Q A
Branch? 6.1
Bug fix? no
New feature? yes
Deprecations? no
Tickets Fix #32622
License MIT
Doc PR symfony/symfony-docs#...

The _default group can be use on the serialization context to explicitly tell the serializer to allow properties without defined @Groups

Exemple:

class User
{

    public $name;

    /**
     * @Groups({"private"})
     */
    public $age;

    /**
     * @Groups({"private", "moderator"})
     */
    public $isBan;
}
  • With no context groups: name, age, isBan
  • With moderator context group: isBan
  • With * context group: name, age, isBan
  • With _default context group: name
  • With _default and moderator context groups: name, isBan

I use the _default keyword here but it can be easily changed for something else like I said in this issue #32622 (comment)

I don't know what could be the best option to reduce the BC break.

  • A special char, like for the *. Could be _. (not a fan of this solution)
  • A special word, like Default in the JMS Serializer (high chance of BC breaks with existing project)
  • The null value
  • The empty string value

null or empty string value cannot be use in @Groups annotation, so we are sure there is no BC break with this solution

@carsonbot
Copy link

Hey!

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

Cheers!

Carsonbot

@noemi-salaun
Copy link
Contributor Author

Anyone available to help me with this PR?

@fabpot fabpot modified the milestones: 6.1, 6.2 May 20, 2022
@noemi-salaun noemi-salaun force-pushed the feat32622-serializer-default-group branch from cfdef73 to 4efbc42 Compare May 23, 2022 08:05
@TerjeBr
Copy link

TerjeBr commented Jul 7, 2022

I am waiting on this. What is holding this up?

@ninsuo
Copy link

ninsuo commented Sep 18, 2022

Hello,
I'm coming back on this, can we somehow help on what blocks the PR?
Have a nice week,
Alain

Copy link
Member

@fabpot fabpot left a comment

Choose a reason for hiding this comment

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


private function getAttributeGroups(AttributeMetadataInterface $serializerAttributeMetadata): array
{
$groups = empty($serializerAttributeMetadata->getGroups()) ? [AbstractNormalizer::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $serializerAttributeMetadata->getGroups();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
$groups = empty($serializerAttributeMetadata->getGroups()) ? [AbstractNormalizer::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $serializerAttributeMetadata->getGroups();
$groups = !$serializerAttributeMetadata->getGroups() ? [AbstractNormalizer::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $serializerAttributeMetadata->getGroups();

Copy link
Member

Choose a reason for hiding this comment

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

Calling getGroups() two times isn't necessary. Storing the result of this function in a variable will improve the performance.

@@ -257,6 +263,13 @@ protected function getGroups(array $context): array
return is_scalar($groups) ? (array) $groups : $groups;
}

protected function getAttributeGroups(AttributeMetadataInterface $attributeMetadata): array
{
$groups = empty($attributeMetadata->getGroups()) ? [self::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $attributeMetadata->getGroups();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
$groups = empty($attributeMetadata->getGroups()) ? [self::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $attributeMetadata->getGroups();
$groups = !$attributeMetadata->getGroups() ? [self::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $attributeMetadata->getGroups();

Copy link
Contributor

Choose a reason for hiding this comment

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

Or even

$groups = $attributeMetadata->getGroups() ?: [self::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS];

@@ -112,6 +112,12 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
*/
public const IGNORED_ATTRIBUTES = 'ignored_attributes';

/**
* The default group can be use on the serialization context to explicitly
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* The default group can be use on the serialization context to explicitly
* The default group can be used on the serialization context to explicitly

@dunglas
Copy link
Member

dunglas commented Sep 20, 2022

Couldn't we use the same conventions as for the Validator component for consistency?

@TerjeBr
Copy link

TerjeBr commented Sep 20, 2022

Couldn't we use the same conventions as for the Validator component for consistency?

By that you mean use the group name "Default" instead of "_default"? Yes, I am in favour of that. (The only problem is that it is a BC break for code that already uses the group name "Default")

@dunglas
Copy link
Member

dunglas commented Sep 20, 2022

Yes, I mean that, and also support using the name of the class as a group name (User in the example provided in the docs).

Regarding the BC break, isn't using _default a BC break too?


private function getAttributeGroups(AttributeMetadataInterface $serializerAttributeMetadata): array
{
$groups = empty($serializerAttributeMetadata->getGroups()) ? [AbstractNormalizer::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $serializerAttributeMetadata->getGroups();
Copy link
Member

Choose a reason for hiding this comment

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

Calling getGroups() two times isn't necessary. Storing the result of this function in a variable will improve the performance.

{
$groups = empty($serializerAttributeMetadata->getGroups()) ? [AbstractNormalizer::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $serializerAttributeMetadata->getGroups();

return array_merge($groups, ['*']);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return array_merge($groups, ['*']);
$groups[] = '*';
return $groups;

This will also probably be a bit faster.

@@ -257,6 +263,13 @@ protected function getGroups(array $context): array
return is_scalar($groups) ? (array) $groups : $groups;
}

protected function getAttributeGroups(AttributeMetadataInterface $attributeMetadata): array
Copy link
Member

Choose a reason for hiding this comment

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

This is on the hot patch. Introducing a new function will have a significant performance impact when serializing a large set of data. Also, we try to not add new protected methods in this class (we're in the process of splitting it and using composition instead of inheritance).

Could you inline it? By the way, you should also inline the one in the extractor.

@@ -257,6 +263,13 @@ protected function getGroups(array $context): array
return is_scalar($groups) ? (array) $groups : $groups;
}

protected function getAttributeGroups(AttributeMetadataInterface $attributeMetadata): array
{
$groups = empty($attributeMetadata->getGroups()) ? [self::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS] : $attributeMetadata->getGroups();
Copy link
Contributor

Choose a reason for hiding this comment

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

Or even

$groups = $attributeMetadata->getGroups() ?: [self::DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS];

* The default group can be use on the serialization context to explicitly
* tell the serializer to allow properties without defined groups.
*/
public const DEFAULT_GROUP_FOR_ATTRIBUTE_WITHOUT_GROUPS = '_default';
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this supposed to be overridden in the userland?
If not, we could mark it as final I guess, and maybe move it on top of L36 so that it's not considered as a context constant.
If yes, then why not store it in the context (and update the AbstractNormalizerContextBuilder)?

@nicolas-grekas nicolas-grekas modified the milestones: 6.2, 6.3 Nov 5, 2022
@nicolas-grekas nicolas-grekas modified the milestones: 6.3, 6.4 May 23, 2023
@nicolas-grekas nicolas-grekas modified the milestones: 6.4, 7.1 Nov 15, 2023
@nicolas-grekas
Copy link
Member

Closing in favor of #51514, thanks for pushing this forward!

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.

Serializer default groups
10 participants