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

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

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
namespace Symfony\Component\PropertyInfo\Extractor;

use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;

/**
* Lists available properties using Symfony Serializer Component metadata.
Expand Down Expand Up @@ -48,11 +50,18 @@ public function getProperties(string $class, array $context = []): ?array

foreach ($serializerClassMetadata->getAttributesMetadata() as $serializerAttributeMetadata) {
$ignored = method_exists($serializerAttributeMetadata, 'isIgnored') && $serializerAttributeMetadata->isIgnored();
if (!$ignored && (null === $context['serializer_groups'] || array_intersect($context['serializer_groups'], $serializerAttributeMetadata->getGroups()))) {
if (!$ignored && (null === $context['serializer_groups'] || array_intersect($context['serializer_groups'], $this->getAttributeGroups($serializerAttributeMetadata)))) {
$properties[] = $serializerAttributeMetadata->getName();
}
}

return $properties;
}

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.


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.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor;
use Symfony\Component\PropertyInfo\Tests\Fixtures\AdderRemoverDummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\DefaultGroupDummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\IgnorePropertyDummy;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
Expand Down Expand Up @@ -52,4 +53,14 @@ public function testGetPropertiesWithAnyGroup()
{
$this->assertSame(['analyses', 'feet'], $this->extractor->getProperties(AdderRemoverDummy::class, ['serializer_groups' => null]));
}

public function testGetPropertiesWithAllGroup()
{
$this->assertSame(['somethingWithoutGroup', 'somethingWithGroup'], $this->extractor->getProperties(DefaultGroupDummy::class, ['serializer_groups' => ['*']]));
}

public function testGetPropertiesWithDefaultGroup()
{
$this->assertSame(['somethingWithoutGroup'], $this->extractor->getProperties(DefaultGroupDummy::class, ['serializer_groups' => ['_default']]));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);

namespace Symfony\Component\PropertyInfo\Tests\Fixtures;

use Symfony\Component\Serializer\Annotation\Groups;

final class DefaultGroupDummy
{

public $somethingWithoutGroup;

/**
* @Groups({"a"})
*/
public $somethingWithGroup;
}
1 change: 1 addition & 0 deletions src/Symfony/Component/Serializer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ CHANGELOG
* Return empty collections as `ArrayObject` from `Serializer::normalize()` when `PRESERVE_EMPTY_OBJECTS` is set
* Add support for collecting type errors during denormalization
* Add missing arguments in `MissingConstructorArgumentsException`
* Add `_default` group serialization context that allow serializing properties without explicit group

5.3
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

* 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)?


/**
* @internal
*/
Expand Down Expand Up @@ -235,7 +241,7 @@ protected function getAllowedAttributes(string|object $classOrObject, array $con
// If you update this check, update accordingly the one in Symfony\Component\PropertyInfo\Extractor\SerializerExtractor::getProperties()
if (
!$ignore &&
([] === $groups || array_intersect(array_merge($attributeMetadata->getGroups(), ['*']), $groups)) &&
([] === $groups || array_intersect($this->getAttributeGroups($attributeMetadata), $groups)) &&
$this->isAllowedAttribute($classOrObject, $name = $attributeMetadata->getName(), null, $context)
) {
$allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata;
Expand All @@ -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.

{
$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];


return array_merge($groups, ['*']);
}

/**
* Is this attribute allowed?
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ public function testGetAllowedAttributesAsString()

$result = $this->normalizer->getAllowedAttributes('c', [AbstractNormalizer::GROUPS => ['*']], true);
$this->assertEquals(['a1', 'a2', 'a3', 'a4'], $result);

$result = $this->normalizer->getAllowedAttributes('c', [AbstractNormalizer::GROUPS => ['_default']], true);
$this->assertEquals(['a1'], $result);
}

public function testGetAllowedAttributesAsObjects()
Expand Down Expand Up @@ -122,6 +125,9 @@ public function testGetAllowedAttributesAsObjects()

$result = $this->normalizer->getAllowedAttributes('c', [AbstractNormalizer::GROUPS => ['*']], false);
$this->assertEquals([$a1, $a2, $a3, $a4], $result);

$result = $this->normalizer->getAllowedAttributes('c', [AbstractNormalizer::GROUPS => ['_default']], false);
$this->assertEquals([$a1], $result);
}

public function testObjectWithStaticConstructor()
Expand Down