core icon indicating copy to clipboard operation
core copied to clipboard

Special '*' serialization group

Open SergeyCherenkov opened this issue 1 year ago • 3 comments

Description

The SymfonySerializer has a special group * that allows you to serialize all fields.

https://github.com/symfony/symfony/pull/33540 https://github.com/symfony/symfony/issues/32622 https://github.com/symfony/symfony/commit/de58759a37fc1e268c91bc56da2e77459cb8f2aa

The SerializerPropertyMetadataFactory treats it as a regular group.

namespace ApiPlatform\Metadata\Property\Factory;

final class SerializerPropertyMetadataFactory implements PropertyMetadataFactoryInterface
{
    // ...
    private function transformReadWrite(ApiProperty $propertyMetadata, string $resourceClass, string $propertyName, ?array $normalizationGroups = null, ?array $denormalizationGroups = null): ApiProperty
    {
        $serializerAttributeMetadata = $this->getSerializerAttributeMetadata($resourceClass, $propertyName);
        $groups = $serializerAttributeMetadata ? $serializerAttributeMetadata->getGroups() : [];
        $ignored = $serializerAttributeMetadata && $serializerAttributeMetadata->isIgnored();

        if (false !== $propertyMetadata->isReadable()) {
            $propertyMetadata = $propertyMetadata->withReadable(!$ignored && (null === $normalizationGroups || array_intersect($normalizationGroups, $groups)));
        }

        if (false !== $propertyMetadata->isWritable()) {
            $propertyMetadata = $propertyMetadata->withWritable(!$ignored && (null === $denormalizationGroups || array_intersect($denormalizationGroups, $groups)));
        }

        return $propertyMetadata;
    }
    // ...
}

Wouldn't it be correct to add handling for this group in API Platform?

SergeyCherenkov avatar Nov 25 '24 10:11 SergeyCherenkov

I propose the following solution (I think it's also applicable for denormalization).

namespace ApiPlatform\Metadata\Property\Factory;

final class SerializerPropertyMetadataFactory implements PropertyMetadataFactoryInterface
{
    // ...
    private function transformReadWrite(ApiProperty $propertyMetadata, string $resourceClass, string $propertyName, ?array $normalizationGroups = null, ?array $denormalizationGroups = null): ApiProperty
    {
        $serializerAttributeMetadata = $this->getSerializerAttributeMetadata($resourceClass, $propertyName);
        $groups = $serializerAttributeMetadata ? $serializerAttributeMetadata->getGroups() : [];
        $groups = array_merge($groups, ['*']); // new line

        $ignored = $serializerAttributeMetadata && $serializerAttributeMetadata->isIgnored();

        if (false !== $propertyMetadata->isReadable()) {
            $propertyMetadata = $propertyMetadata->withReadable(!$ignored && (null === $normalizationGroups || array_intersect($normalizationGroups, $groups)));
        }

        if (false !== $propertyMetadata->isWritable()) {
            $propertyMetadata = $propertyMetadata->withWritable(!$ignored && (null === $denormalizationGroups || array_intersect($denormalizationGroups, $groups)));
        }

        return $propertyMetadata;
    }
    // ...
}

If this is a correct solution, I can create a PR.

SergeyCherenkov avatar Nov 25 '24 10:11 SergeyCherenkov

Shouldn't the * group be opt-in? What behavior should change in our code? I guess that this makes properties readable/writable if they've a group? poke @dunglas

soyuka avatar Dec 16 '24 08:12 soyuka

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Feb 14 '25 16:02 stale[bot]